Skip to content

Commit

Permalink
feat: add ccapi to application samples (#780)
Browse files Browse the repository at this point in the history
* feat: add ccapi

Signed-off-by: osamamagdy <[email protected]>

* fix: fix linting errors

Signed-off-by: osamamagdy <[email protected]>

* fix: add go mod for ccapi

Signed-off-by: osamamagdy <[email protected]>

* fix: edit go mod to use fpc from main commit

Signed-off-by: osamamagdy <[email protected]>

* fix: edit path

Signed-off-by: osamamagdy <[email protected]>

* fix: remove go mod vendor from dockerfile

Signed-off-by: osamamagdy <[email protected]>

* doc: cd into ccapi before running

Signed-off-by: osamamagdy <[email protected]>

* feat: remove hardcoded org name

Signed-off-by: osamamagdy <[email protected]>

* feat: edit ccapi to be just an extension

Signed-off-by: osamamagdy <[email protected]>

* fix: add the org name for scripts

Signed-off-by: osamamagdy <[email protected]>

* fix: export CORE_PEER_ORG_NAME

Signed-off-by: osamamagdy <[email protected]>

* docs: edit readme

Signed-off-by: osamamagdy <[email protected]>

* docs: add notes for ccapi

Signed-off-by: Osama Magdy <[email protected]>

---------

Signed-off-by: osamamagdy <[email protected]>
Signed-off-by: Osama Magdy <[email protected]>
  • Loading branch information
osamamagdy authored Jan 31, 2025
1 parent 88b7c21 commit 805e428
Show file tree
Hide file tree
Showing 35 changed files with 3,900 additions and 1 deletion.
Binary file added samples/application/ccapi/CCAPIFlow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions samples/application/ccapi/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Use an official Golang runtime as a parent image
FROM golang:1.21-alpine AS build

ENV PATH="${PATH}:/usr/bin/"

RUN apk update

RUN apk add \
docker \
openrc \
git \
gcc \
gcompat \
libc-dev \
libc6-compat \
libstdc++ && \
ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2

# Set the working directory to /rest-server
WORKDIR /rest-server

# Copy the go.mod and go.sum files for dependency management
COPY go.mod go.sum ./

# Install go dependencies
RUN go mod download

# Copy the current directory contents into the container at /rest-server
COPY . .

# Build the Go ccapi
RUN go build -o ccapi

# # Use an official Alpine runtime as a parent image
# FROM alpine:latest

# ENV PATH="${PATH}:/usr/bin/"

# RUN apk update

# RUN apk add \
# docker \
# openrc \
# git \
# gcc \
# gcompat \
# libc-dev \
# libc6-compat \
# libstdc++ && \
# ln -s /lib/libc.so.6 /usr/lib/libresolv.so.2

# # Set the working directory to /rest-server
# WORKDIR /rest-server

# Copy the ccapi binary from the build container to the current directory in the Alpine container
RUN ls -l
RUN pwd

RUN cp ./ccapi /usr/bin/ccapi

# Run the ccapi binary
CMD ["ccapi"]
39 changes: 39 additions & 0 deletions samples/application/ccapi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# CCAPI - A web server developed to interface with CC-tools chaincode

## Motivation

As continuation to the [cc-tools-demo]() tutorial on how to integrate the cc-tools project with FPC chaincodes, we start by utilizing another powerful solution offered by cc-tools which is the CCAPI. It's a complete web server that simplifies the communication with the peers and Fabric components to replace the need to deal with CLI applications.

## Architecture

The following diagram explains the process where we modified the API server developed for a demo on cc-tools ([CCAPI](https://github.com/hyperledger-labs/cc-tools-demo/tree/main/ccapi)) and modified it to communicate with FPC code.

The transaction client invocation process, as illustrated in the diagram, consists of several key steps that require careful integration between FPC and cc-tools.

1. Step 1-2: The API server is listening for requests on a specified port over an HTTP channel and sends it to the handler.
2. Step 3: The handler starts by determining the appropriate transaction invocation based on the requested endpoint and calling the corresponding chaincode API.
3. Step 4: The chaincode API is responsible for parsing and ensuring the payload is correctly parsed into a format that is FPC-friendly. This parsing step is crucial, as it prepares the data to meet FPC’s privacy and security requirements before it reaches the peer.
4. Step 5: FPCUtils is the step where the actual transaction invocation happens. It follows the steps explained in [here](https://github.com/hyperledger/fabric-rfcs/blob/main/text/0000-fabric-private-chaincode-1.0.md#fpc-transaction-flow) as it builds on top of the FPC Client SDK.

![CCAPIFlow](./CCAPIFlow.png)

## User Experience

CCAPI uses docker and docker-compose to spin up all the required components to work.

Have a look at the [fpc-docker-compose.yaml](./fpc-docker-compose.yaml) to see how we use different env vars. Most of these environment variables are required by any client application to work and communicate with FPC. If you followed the [cc-tools-demo](../../chaincode/cc-tools-demo/README.md) tutorial, the values should be the same.

Note: The following steps should run outside the FPC dev container

Start by running:

```bash
cd $FPC_PATH/samples/application/ccapi
docker-compose -f fpc-docker-compose.yaml up
```

then go to the browser and type `localhost:80` to open the swagger api and start executing functions.

## Future work

CCAPI has another component for the dashboard frontend application but it's not yet utilized with
24 changes: 24 additions & 0 deletions samples/application/ccapi/chaincode/invokeFPC.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
"net/http"

"github.com/hyperledger/fabric-private-chaincode/samples/application/ccapi/common"
)

func InvokeFpc(channelName string, chaincodeName string, txname string, args [][]byte) ([]byte, int, error) {
stringArgs := make([]string, len(args))
for i, b := range args {
stringArgs[i] = string(b)
}

client := common.NewFpcClient(channelName, chaincodeName)
res := client.Invoke(txname, stringArgs[0:]...)
return []byte(res), http.StatusOK, nil
}
24 changes: 24 additions & 0 deletions samples/application/ccapi/chaincode/invokeFPCDefault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
"net/http"

"github.com/hyperledger/fabric-private-chaincode/samples/application/ccapi/common"
)

func InvokeFpcDefault(txname string, args [][]byte) ([]byte, int, error) {
stringArgs := make([]string, len(args))
for i, b := range args {
stringArgs[i] = string(b)
}

client := common.NewDefaultFpcClient()
res := client.Invoke(txname, stringArgs[0:]...)
return []byte(res), http.StatusOK, nil
}
24 changes: 24 additions & 0 deletions samples/application/ccapi/chaincode/queryFPC.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
"net/http"

"github.com/hyperledger/fabric-private-chaincode/samples/application/ccapi/common"
)

func QueryFpc(chaincodeName string, channelName string, txName string, args [][]byte) ([]byte, int, error) {
stringArgs := make([]string, len(args))
for i, b := range args {
stringArgs[i] = string(b)
}

client := common.NewFpcClient(chaincodeName, channelName)
res := client.Query(txName, stringArgs[0:]...)
return []byte(res), http.StatusOK, nil
}
24 changes: 24 additions & 0 deletions samples/application/ccapi/chaincode/queryFPCDefault.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package chaincode

import (
"net/http"

"github.com/hyperledger/fabric-private-chaincode/samples/application/ccapi/common"
)

func QueryFpcDefault(txName string, args [][]byte) ([]byte, int, error) {
stringArgs := make([]string, len(args))
for i, b := range args {
stringArgs[i] = string(b)
}

client := common.NewDefaultFpcClient()
res := client.Query(txName, stringArgs[0:]...)
return []byte(res), http.StatusOK, nil
}
69 changes: 69 additions & 0 deletions samples/application/ccapi/common/fpc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package common

import (
"fmt"
"os"
"strconv"

pkgFpc "github.com/hyperledger/fabric-private-chaincode/samples/application/ccapi/fpcUtils"
)

var (
defaultFpcConfig *pkgFpc.Config
)

func InitFpcConfig() {

getStrEnv := func(key string) string {
val := os.Getenv(key)
if val == "" {
panic(fmt.Sprintf("%s not set", key))
}
return val
}

getBoolEnv := func(key string) bool {
val := getStrEnv(key)
ret, err := strconv.ParseBool(val)
if err != nil {
if val == "" {
panic(fmt.Sprintf("invalid bool value for %s", key))
}
}
return ret
}

defaultFpcConfig = &pkgFpc.Config{
CorePeerAddress: getStrEnv("CORE_PEER_ADDRESS"),
CorePeerId: getStrEnv("CORE_PEER_ID"),
CorePeerOrgName: getStrEnv("CORE_PEER_ORG_NAME"),
CorePeerLocalMSPID: getStrEnv("CORE_PEER_LOCALMSPID"),
CorePeerMSPConfigPath: getStrEnv("CORE_PEER_MSPCONFIGPATH"),
CorePeerTLSCertFile: getStrEnv("CORE_PEER_TLS_CERT_FILE"),
CorePeerTLSEnabled: getBoolEnv("CORE_PEER_TLS_ENABLED"),
CorePeerTLSKeyFile: getStrEnv("CORE_PEER_TLS_KEY_FILE"),
CorePeerTLSRootCertFile: getStrEnv("CORE_PEER_TLS_ROOTCERT_FILE"),
OrdererCA: getStrEnv("ORDERER_CA"),
ChaincodeId: getStrEnv("CCNAME"),
ChannelId: getStrEnv("CHANNEL"),
GatewayConfigPath: getStrEnv("GATEWAY_CONFIG"),
}

}

func NewDefaultFpcClient() *pkgFpc.Client {
return pkgFpc.NewClient(defaultFpcConfig)
}

func NewFpcClient(channelName string, chaincodeName string) *pkgFpc.Client {
fpcConfig := defaultFpcConfig
fpcConfig.ChannelId = channelName
fpcConfig.ChaincodeId = chaincodeName
return pkgFpc.NewClient(fpcConfig)
}
Loading

0 comments on commit 805e428

Please sign in to comment.