diff --git a/samples/application/ccapi/CCAPIFlow.png b/samples/application/ccapi/CCAPIFlow.png deleted file mode 100644 index 17e8dfcf7..000000000 Binary files a/samples/application/ccapi/CCAPIFlow.png and /dev/null differ diff --git a/samples/application/ccapi/Dockerfile b/samples/application/ccapi/Dockerfile deleted file mode 100644 index 725748381..000000000 --- a/samples/application/ccapi/Dockerfile +++ /dev/null @@ -1,61 +0,0 @@ -# Use an official Golang runtime as a parent image -FROM golang:1.19-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 - -RUN go mod vendor - -# 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 -COPY --from=build /rest-server/ccapi /usr/bin/ccapi - -# Run the ccapi binary -CMD ["ccapi"] \ No newline at end of file diff --git a/samples/application/ccapi/README.md b/samples/application/ccapi/README.md deleted file mode 100644 index 8f1fb7f86..000000000 --- a/samples/application/ccapi/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# 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 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 and it follows the steps explained in the previous diagram as it builds on top of the FPC Client SDK. - -![CCAPIFlow](./CCAPIFlow.png) - -## User Experience - -CCAPI is using docker and docker-compose for spinning up all the required components needed 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. - -Start by running `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 have another component for the dashboard frontend application but it's not yet utilized with diff --git a/samples/application/ccapi/chaincode/event.go b/samples/application/ccapi/chaincode/event.go deleted file mode 100644 index 0db0f9090..000000000 --- a/samples/application/ccapi/chaincode/event.go +++ /dev/null @@ -1,145 +0,0 @@ -package chaincode - -import ( - "encoding/json" - "fmt" - "log" - "os" - "regexp" - - "github.com/hyperledger-labs/ccapi/common" - ev "github.com/hyperledger/fabric-sdk-go/pkg/client/event" - "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" -) - -func getEventClient(channelName string) (*ev.Client, error) { - // create channel manager - fabMngr, err := common.NewFabricChClient(channelName, os.Getenv("USER"), os.Getenv("ORG")) - if err != nil { - return nil, err - } - - // Create event client - ec, err := ev.New(fabMngr.Provider, ev.WithBlockEvents()) - if err != nil { - return nil, err - } - - return ec, nil -} - -func WaitForEvent(channelName, ccName, eventName string, fn func(*fab.CCEvent)) { - ec, err := getEventClient(channelName) - if err != nil { - log.Println("error getting event client: ", err) - return - } - - for { - // Register chaincode event - registration, notifier, err := ec.RegisterChaincodeEvent(ccName, eventName) - if err != nil { - log.Println("error registering chaincode event: ", err) - return - } - - // Execute handler function on event notification - ccEvent := <-notifier - fmt.Printf("Received CC event: %v\n", ccEvent) - fn(ccEvent) - - ec.Unregister(registration) - } -} - -func HandleEvent(channelName, ccName string, event EventHandler) { - ec, err := getEventClient(channelName) - if err != nil { - log.Println("error getting event client: ", err) - return - } - - for { - // Register chaincode event - registration, notifier, err := ec.RegisterChaincodeEvent(ccName, event.Tag) - if err != nil { - log.Println("error registering chaincode event: ", err) - return - } - - // Execute handler function on event notification - ccEvent := <-notifier - fmt.Printf("Received CC event: %v\n", ccEvent) - event.Execute(ccEvent) - - ec.Unregister(registration) - } -} - -func RegisterForEvents() { - // Get registered events on the chaincode - res, _, err := Invoke(os.Getenv("CHANNEL"), os.Getenv("CCNAME"), "getEvents", os.Getenv("USER"), nil, nil) - if err != nil { - fmt.Println("error registering for events: ", err) - return - } - - var events []interface{} - nerr := json.Unmarshal(res.Payload, &events) - if nerr != nil { - fmt.Println("error unmarshalling events: ", nerr) - return - } - - msp := common.GetClientOrg() + "MSP" - - for _, event := range events { - eventMap := event.(map[string]interface{}) - receiverArr, ok := eventMap["receivers"] - - isReceiver := true - // Verify if the MSP is a receiver for the event - if ok { - isReceiver = false - receivers := receiverArr.([]interface{}) - for _, r := range receivers { - receiver := r.(string) - - if len(receiver) <= 1 { - continue - } - if receiver[0] == '$' { - match, err := regexp.MatchString(receiver[1:], msp) - if err != nil { - fmt.Println("error matching regexp: ", err) - return - } - if match { - isReceiver = true - break - } - } else { - if receiver == msp { - isReceiver = true - break - } - } - } - } - - if isReceiver { - eventHandler := EventHandler{ - Tag: eventMap["tag"].(string), - Type: EventType(eventMap["type"].(float64)), - Transaction: eventMap["transaction"].(string), - Channel: eventMap["channel"].(string), - Chaincode: eventMap["chaincode"].(string), - Label: eventMap["label"].(string), - BaseLog: eventMap["baseLog"].(string), - ReadOnly: eventMap["readOnly"].(bool), - } - - go HandleEvent(os.Getenv("CHANNEL"), os.Getenv("CCNAME"), eventHandler) - } - } -} diff --git a/samples/application/ccapi/chaincode/eventHandler.go b/samples/application/ccapi/chaincode/eventHandler.go deleted file mode 100644 index 07b72f988..000000000 --- a/samples/application/ccapi/chaincode/eventHandler.go +++ /dev/null @@ -1,97 +0,0 @@ -package chaincode - -import ( - b64 "encoding/base64" - "encoding/json" - "fmt" - "os" - - "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" -) - -type EventType float64 - -const ( - EventLog EventType = iota - EventTransaction - EventCustom -) - -type EventHandler struct { - Tag string - Label string - Type EventType - Transaction string - Channel string - Chaincode string - BaseLog string - ReadOnly bool -} - -func (event EventHandler) Execute(ccEvent *fab.CCEvent) { - if len(event.BaseLog) > 0 { - fmt.Println(event.BaseLog) - } - - if event.Type == EventLog { - var logStr string - nerr := json.Unmarshal(ccEvent.Payload, &logStr) - if nerr != nil { - fmt.Println("error unmarshalling log: ", nerr) - return - } - - if len(logStr) > 0 { - fmt.Println("Event '", event.Label, "' log: ", logStr) - } - } else if event.Type == EventTransaction { - ch := os.Getenv("CHANNEL") - if event.Channel != "" { - ch = event.Channel - } - cc := os.Getenv("CCNAME") - if event.Chaincode != "" { - cc = event.Chaincode - } - - res, _, err := Invoke(ch, cc, event.Transaction, os.Getenv("USER"), [][]byte{ccEvent.Payload}, nil) - if err != nil { - fmt.Println("error invoking transaction: ", err) - return - } - - var response map[string]interface{} - nerr := json.Unmarshal(res.Payload, &response) - if nerr != nil { - fmt.Println("error unmarshalling response: ", nerr) - return - } - fmt.Println("Response: ", response) - } else if event.Type == EventCustom { - // Encode payload to base64 - b64Encode := b64.StdEncoding.EncodeToString([]byte(ccEvent.Payload)) - - args, ok := json.Marshal(map[string]interface{}{ - "eventTag": event.Tag, - "payload": b64Encode, - }) - if ok != nil { - fmt.Println("failed to encode args to JSON format") - return - } - - // Invoke tx - txName := "executeEvent" - if event.ReadOnly { - txName = "runEvent" - } - - _, _, err := Invoke(os.Getenv("CHANNEL"), os.Getenv("CCNAME"), txName, os.Getenv("USER"), [][]byte{args}, nil) - if err != nil { - fmt.Println("error invoking transaction: ", err) - return - } - } else { - fmt.Println("Event type not supported") - } -} diff --git a/samples/application/ccapi/chaincode/invoke.go b/samples/application/ccapi/chaincode/invoke.go deleted file mode 100644 index b9030597a..000000000 --- a/samples/application/ccapi/chaincode/invoke.go +++ /dev/null @@ -1,37 +0,0 @@ -package chaincode - -import ( - "net/http" - "os" - - "github.com/hyperledger-labs/ccapi/common" - "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" - "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" -) - -func Invoke(channelName, ccName, txName, user string, txArgs [][]byte, transientRequest []byte) (*channel.Response, int, error) { - // create channel manager - fabMngr, err := common.NewFabricChClient(channelName, user, os.Getenv("ORG")) - if err != nil { - return nil, http.StatusInternalServerError, err - } - - // Execute chaincode with channel's client - rq := channel.Request{ChaincodeID: ccName, Fcn: txName} - if len(txArgs) > 0 { - rq.Args = txArgs - } - - if len(transientRequest) != 0 { - transientMap := make(map[string][]byte) - transientMap["@request"] = transientRequest - rq.TransientMap = transientMap - } - - res, err := fabMngr.Client.Execute(rq, channel.WithRetry(retry.DefaultChannelOpts)) - if err != nil { - return nil, extractStatusCode(err.Error()), err - } - - return &res, http.StatusOK, nil -} diff --git a/samples/application/ccapi/chaincode/invokeFPC.go b/samples/application/ccapi/chaincode/invokeFPC.go deleted file mode 100644 index d74b29b91..000000000 --- a/samples/application/ccapi/chaincode/invokeFPC.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "net/http" - - "github.com/hyperledger-labs/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 -} diff --git a/samples/application/ccapi/chaincode/invokeFPCDefault.go b/samples/application/ccapi/chaincode/invokeFPCDefault.go deleted file mode 100644 index 11b2a023c..000000000 --- a/samples/application/ccapi/chaincode/invokeFPCDefault.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "net/http" - - "github.com/hyperledger-labs/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 -} diff --git a/samples/application/ccapi/chaincode/invokeGateway.go b/samples/application/ccapi/chaincode/invokeGateway.go deleted file mode 100644 index 2d2edb976..000000000 --- a/samples/application/ccapi/chaincode/invokeGateway.go +++ /dev/null @@ -1,61 +0,0 @@ -package chaincode - -import ( - "os" - - "github.com/hyperledger-labs/ccapi/common" - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/pkg/errors" -) - -func InvokeGateway(channelName, chaincodeName, txName, user string, args []string, transientArgs []byte, endorsingOrgs []string) ([]byte, error) { - // Gateway endpoint - endpoint := os.Getenv("FABRIC_GATEWAY_ENDPOINT") - - // Create client grpc connection - grpcConn, err := common.CreateGrpcConnection(endpoint) - if err != nil { - return nil, errors.Wrap(err, "failed to create grpc connection") - } - defer grpcConn.Close() - - // Create gateway connection - gw, err := common.CreateGatewayConnection(grpcConn, user) - if err != nil { - return nil, errors.Wrap(err, "failed to create gateway connection") - } - defer gw.Close() - - // Obtain smart contract deployed on the network. - network := gw.GetNetwork(channelName) - contract := network.GetContract(chaincodeName) - - // Make transient request - transientMap := make(map[string][]byte) - transientMap["@request"] = transientArgs - - // Invoke transaction - if transientArgs != nil && len(endorsingOrgs) > 0 { - return contract.Submit(txName, - client.WithArguments(args...), - client.WithTransient(transientMap), - client.WithEndorsingOrganizations(endorsingOrgs...), - ) - } - - if transientArgs != nil { - return contract.Submit(txName, - client.WithArguments(args...), - client.WithTransient(transientMap), - ) - } - - if len(endorsingOrgs) > 0 { - return contract.Submit(txName, - client.WithArguments(args...), - client.WithEndorsingOrganizations(endorsingOrgs...), - ) - } - - return contract.SubmitTransaction(txName, args...) -} diff --git a/samples/application/ccapi/chaincode/query.go b/samples/application/ccapi/chaincode/query.go deleted file mode 100644 index a069c7be6..000000000 --- a/samples/application/ccapi/chaincode/query.go +++ /dev/null @@ -1,32 +0,0 @@ -package chaincode - -import ( - "net/http" - "os" - - "github.com/hyperledger-labs/ccapi/common" - "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" - "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" -) - -func Query(channelName, ccName, txName, user string, txArgs [][]byte) (*channel.Response, int, error) { - // create channel manager - fabMngr, err := common.NewFabricChClient(channelName, user, os.Getenv("ORG")) - if err != nil { - return nil, http.StatusInternalServerError, err - } - - // Execute chaincode with channel's client - rq := channel.Request{ChaincodeID: ccName, Fcn: txName} - if len(txArgs) > 0 { - rq.Args = txArgs - } - - res, err := fabMngr.Client.Query(rq, channel.WithRetry(retry.DefaultChannelOpts)) - if err != nil { - status := extractStatusCode(err.Error()) - return nil, status, err - } - - return &res, http.StatusOK, nil -} diff --git a/samples/application/ccapi/chaincode/queryFPC.go b/samples/application/ccapi/chaincode/queryFPC.go deleted file mode 100644 index 7f8c8e804..000000000 --- a/samples/application/ccapi/chaincode/queryFPC.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "net/http" - - "github.com/hyperledger-labs/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 -} diff --git a/samples/application/ccapi/chaincode/queryFPCDefault.go b/samples/application/ccapi/chaincode/queryFPCDefault.go deleted file mode 100644 index 8cc7d41d9..000000000 --- a/samples/application/ccapi/chaincode/queryFPCDefault.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "net/http" - - "github.com/hyperledger-labs/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 -} diff --git a/samples/application/ccapi/chaincode/queryGateway.go b/samples/application/ccapi/chaincode/queryGateway.go deleted file mode 100644 index 96e9914f2..000000000 --- a/samples/application/ccapi/chaincode/queryGateway.go +++ /dev/null @@ -1,38 +0,0 @@ -package chaincode - -import ( - "os" - - "github.com/hyperledger-labs/ccapi/common" - "github.com/pkg/errors" -) - -func QueryGateway(channelName, chaincodeName, txName, user string, args []string) ([]byte, error) { - // Gateway endpoint - endpoint := os.Getenv("FABRIC_GATEWAY_ENDPOINT") - - // Create client grpc connection - grpcConn, err := common.CreateGrpcConnection(endpoint) - if err != nil { - return nil, errors.Wrap(err, "failed to create grpc connection") - } - defer grpcConn.Close() - - // Create gateway connection - gw, err := common.CreateGatewayConnection(grpcConn, user) - if err != nil { - return nil, errors.Wrap(err, "failed to create gateway connection") - } - defer gw.Close() - - // Obtain smart contract deployed on the network. - network := gw.GetNetwork(channelName) - contract := network.GetContract(chaincodeName) - - // Query transaction - if len(args) == 0 { - return contract.EvaluateTransaction(txName) - } - - return contract.EvaluateTransaction(txName, args...) -} diff --git a/samples/application/ccapi/chaincode/utils.go b/samples/application/ccapi/chaincode/utils.go deleted file mode 100644 index 6132c9cdd..000000000 --- a/samples/application/ccapi/chaincode/utils.go +++ /dev/null @@ -1,26 +0,0 @@ -package chaincode - -import ( - "fmt" - "net/http" - "regexp" - "strconv" -) - -func extractStatusCode(msg string) int { - re := regexp.MustCompile(`Code:\s*\((\d+)\)`) - - matches := re.FindStringSubmatch(msg) - if len(matches) == 0 { - fmt.Println("No status code found in message") - return http.StatusInternalServerError - } - - statusCode, err := strconv.Atoi(matches[1]) - if err != nil { - fmt.Println("Failed to parse string to int when extracting status code") - return http.StatusInternalServerError - } - - return statusCode -} diff --git a/samples/application/ccapi/common/abort.go b/samples/application/ccapi/common/abort.go deleted file mode 100644 index 669702b84..000000000 --- a/samples/application/ccapi/common/abort.go +++ /dev/null @@ -1,29 +0,0 @@ -package common - -import ( - "net/http" - - "github.com/gin-gonic/gin" -) - -func Abort(c *gin.Context, status int, err error) { - c.JSON(status, gin.H{ - "status": status, - "error": err.Error(), - }) - c.Error(err) -} - -func Respond(c *gin.Context, res interface{}, status int, err error) { - if err != nil { - c.JSON(status, gin.H{ - "response": res, - "status": status, - "error": err.Error(), - }) - c.Error(err) - return - } - - c.JSON(http.StatusOK, res) -} diff --git a/samples/application/ccapi/common/fabsdk.go b/samples/application/ccapi/common/fabsdk.go deleted file mode 100644 index 9d1f1fde5..000000000 --- a/samples/application/ccapi/common/fabsdk.go +++ /dev/null @@ -1,193 +0,0 @@ -package common - -import ( - "fmt" - "log" - "os" - - "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context" - "github.com/hyperledger/fabric-sdk-go/pkg/core/config" - "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" -) - -type sdk struct { - // sdk belongs to org defined in the configsdk.yaml file - Sdk *fabsdk.FabricSDK - Path string -} - -// CreateContext allows creation of transactions using the supplied identity as the credential. -func (s *sdk) CreateClientContext(options ...fabsdk.ContextOption) context.ClientProvider { - return s.Sdk.Context(options...) -} - -func (s *sdk) CreateChannelContext(channelName string, options ...fabsdk.ContextOption) context.ChannelProvider { - return s.Sdk.ChannelContext(channelName, options...) -} - -// Log config path which sdk was created -func (s *sdk) LogPath() { - log.Printf("sdk created from '%s'", s.Path) -} - -// Singleton sdk instance -var instance *sdk - -// GetSDK returns a fabric sdk instance. -// -// A new sdk is created if: -// - it is the first time it is beeing used, or -// - new sdk options are given -// -// Otherwise, it returns the one previoulsy created. -// If options are given, the new sdk is not a singleton, and must -// be closed by whoever invoked it. -// -// The configsdk file can be set via environment variable and defaults -// to './config/configsdk.yaml' -func GetSDK(sdkOpts ...fabsdk.Option) (*sdk, error) { - - // return new sdk instance if sdkOpts are given. - // user must close sdk - if len(sdkOpts) != 0 { - cfgPath := getCfgPath() - configOpt := config.FromFile(cfgPath) - s, err := fabsdk.New(configOpt, sdkOpts...) - - return &sdk{ - Sdk: s, - Path: cfgPath, - }, err - } - - if instance == nil { - cfgPath := getCfgPath() - configOpt := config.FromFile(cfgPath) - s, err := fabsdk.New(configOpt) - if err != nil { - return nil, err - } - - instance = &sdk{ - Sdk: s, - Path: cfgPath, - } - instance.LogPath() - } - - return instance, nil -} - -// getCfgPath parses path for the configsdk -// from environmet, and defaults to './config/configsdk.yaml' -func getCfgPath() (cfgPath string) { - cfgPath = os.Getenv("SDK_PATH") - if cfgPath == "" { - cfgPath = "./config/configsdk.yaml" - } - return -} - -// GetClientOrg returns the name of the client organization -func GetClientOrg() string { - sdk, err := GetSDK() - if err != nil { - return "" - } - - cfg, err := sdk.Sdk.Config() - if err != nil { - return "" - } - - i, ok := cfg.Lookup("client") - if !ok { - return "" - } - m, ok := i.(map[string]interface{}) - if !ok { - return "" - } - - org := m["organization"] - orgName, ok := org.(string) - if !ok { - return "" - } - - return orgName -} - -func GetCryptoPath() string { - sdk, err := GetSDK() - if err != nil { - return "" - } - - cfg, err := sdk.Sdk.Config() - if err != nil { - return "" - } - - i, ok := cfg.Lookup("client.cryptoconfig.path") - if !ok { - return "" - } - basePath, _ := i.(string) - - i, ok = cfg.Lookup(fmt.Sprintf("organizations.%s.cryptoPath", os.Getenv("ORG"))) - if !ok { - return "" - } - - certPath, _ := i.(string) - return basePath + "/" + certPath -} - -func GetTLSCACert() string { - sdk, err := GetSDK() - if err != nil { - return "" - } - - cfg, err := sdk.Sdk.Config() - if err != nil { - return "" - } - - i, ok := cfg.Lookup("client.tlsCerts.client.cacertfile") - if !ok { - return "" - } - - certPath, _ := i.(string) - return certPath -} - -func GetMSPID() string { - sdk, err := GetSDK() - if err != nil { - return "" - } - - cfg, err := sdk.Sdk.Config() - if err != nil { - return "" - } - - i, ok := cfg.Lookup(fmt.Sprintf("organizations.%s.mspid", os.Getenv("ORG"))) - if !ok { - return "" - } - - mspid, _ := i.(string) - return mspid -} - -// Closes sdk instance if it was created -func CloseSDK() { - if instance != nil { - instance.Sdk.Close() - instance = nil - } -} diff --git a/samples/application/ccapi/common/fpc.go b/samples/application/ccapi/common/fpc.go deleted file mode 100644 index d752c8b90..000000000 --- a/samples/application/ccapi/common/fpc.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package common - -import ( - "fmt" - "os" - "strconv" - - pkgFpc "github.com/hyperledger-labs/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"), - 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) -} diff --git a/samples/application/ccapi/common/gateway.go b/samples/application/ccapi/common/gateway.go deleted file mode 100644 index 16c6decbe..000000000 --- a/samples/application/ccapi/common/gateway.go +++ /dev/null @@ -1,198 +0,0 @@ -package common - -import ( - "context" - "crypto/x509" - "fmt" - "net/http" - "os" - "regexp" - "strconv" - "strings" - "time" - - "github.com/hyperledger/fabric-gateway/pkg/client" - "github.com/hyperledger/fabric-gateway/pkg/identity" - "github.com/hyperledger/fabric-protos-go-apiv2/gateway" - "github.com/pkg/errors" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/status" -) - -var ( - gatewayTLSCredentials *credentials.TransportCredentials -) - -func CreateGrpcConnection(endpoint string) (*grpc.ClientConn, error) { - // Check TLS credential was created - if gatewayTLSCredentials == nil { - gatewayServerName := os.Getenv("FABRIC_GATEWAY_NAME") - - cred, err := createTransportCredential(GetTLSCACert(), gatewayServerName) - if err != nil { - return nil, errors.Wrap(err, "failed to create tls credentials") - } - - gatewayTLSCredentials = &cred - } - - // Create client grpc connection - return grpc.Dial(endpoint, grpc.WithTransportCredentials(*gatewayTLSCredentials)) -} - -func CreateGatewayConnection(grpcConn *grpc.ClientConn, user string) (*client.Gateway, error) { - // Create identity - id, err := newIdentity(getSignCert(user), GetMSPID()) - if err != nil { - return nil, errors.Wrap(err, "failed to create new identity") - } - gatewayId := id - - // Create sign function - sign, err := newSign(getSignKey(user)) - if err != nil { - return nil, errors.Wrap(err, "failed to create new sign function") - } - - gatewaySign := sign - - // Create a Gateway connection for a specific client identity. - return client.Connect( - gatewayId, - client.WithSign(gatewaySign), - client.WithClientConnection(grpcConn), - - // 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), - ) -} - -// Create transport credential -func createTransportCredential(tlsCertPath, serverName string) (credentials.TransportCredentials, error) { - certificate, err := loadCertificate(tlsCertPath) - if err != nil { - return nil, err - } - - certPool := x509.NewCertPool() - certPool.AddCert(certificate) - return credentials.NewClientTLSFromCert(certPool, serverName), nil -} - -// Creates a client identity for a gateway connection using an X.509 certificate. -func newIdentity(certPath, mspID string) (*identity.X509Identity, error) { - certificate, err := loadCertificate(certPath) - if err != nil { - return nil, err - } - - id, err := identity.NewX509Identity(mspID, certificate) - if err != nil { - return nil, err - } - - return id, nil -} - -// Creates a function that generates a digital signature from a message digest using a private key. -func newSign(keyPath string) (identity.Sign, error) { - privateKeyPEM, err := os.ReadFile(keyPath) - if err != nil { - return nil, errors.Wrap(err, "failed to read private key file") - } - - privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) - if err != nil { - return nil, err - } - - sign, err := identity.NewPrivateKeySign(privateKey) - if err != nil { - return nil, errors.Wrap(err, "failed to create signer function") - } - - return sign, nil -} - -// Returns error and status code -func ParseError(err error) (error, int) { - var errMsg string - - switch err := err.(type) { - case *client.EndorseError: - errMsg = "endorse error for transaction" - case *client.SubmitError: - errMsg = "submit error for transaction" - case *client.CommitStatusError: - if errors.Is(err, context.DeadlineExceeded) { - errMsg = "timeout waiting for transaction commit status" - } else { - errMsg = "error obtaining commit status for transaction" - } - case *client.CommitError: - errMsg = "transaction failed to commit" - default: - errMsg = "unexpected error type:" + err.Error() - } - - statusErr := status.Convert(err) - - details := statusErr.Details() - if len(details) == 0 { - return errors.New(errMsg), http.StatusInternalServerError - } - - for _, detail := range details { - switch detail := detail.(type) { - case *gateway.ErrorDetail: - status, msg := extractStatusAndMessage(detail.Message) - return errors.New(msg), status - } - } - - return errors.New(errMsg), http.StatusInternalServerError -} - -func extractStatusAndMessage(msg string) (int, string) { - pattern := `chaincode response (\b(\d{3})\b), ` - reg := regexp.MustCompile(pattern) - matches := reg.FindStringSubmatch(msg) - - if len(matches) == 0 { - return http.StatusInternalServerError, msg - } - - errMsg := strings.Replace(msg, matches[0], "", 1) - status, err := strconv.Atoi(matches[1]) - if err != nil { - status = http.StatusInternalServerError - } - - return status, errMsg -} - -func loadCertificate(filename string) (*x509.Certificate, error) { - certificatePEM, err := os.ReadFile(filename) - if err != nil { - return nil, fmt.Errorf("failed to read certificate file: %w", err) - } - return identity.CertificateFromPEM(certificatePEM) -} - -func getSignCert(user string) string { - cryptoPath := GetCryptoPath() - filename := user + "@" + os.Getenv("ORG") + "." + os.Getenv("DOMAIN") + "-cert.pem" - - return strings.Replace(cryptoPath, "{username}", user, 1) + "/signcerts/" + filename -} - -func getSignKey(user string) string { - cryptoPath := GetCryptoPath() - filename := "priv_sk" - - return strings.Replace(cryptoPath, "{username}", user, 1) + "/keystore/" + filename -} diff --git a/samples/application/ccapi/common/resmgnt.go b/samples/application/ccapi/common/resmgnt.go deleted file mode 100644 index 301b8761e..000000000 --- a/samples/application/ccapi/common/resmgnt.go +++ /dev/null @@ -1,110 +0,0 @@ -package common - -import ( - "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" - "github.com/hyperledger/fabric-sdk-go/pkg/client/ledger" - "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" - "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/context" - "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" -) - -type fabricResmgtmClient struct { - Provider context.ClientProvider - Client *resmgmt.Client -} -type fabricChannelClient struct { - Provider context.ChannelProvider - Client *channel.Client -} -type fabricLedgerClient struct { - Provider context.ChannelProvider - Client *ledger.Client -} - -// Returns a client which has access resource management capabilities -// These are, but not limited to: create channel, query cfg, cc lifecycle... -// -// Function works like this: -// 1. Get sdk -// 2. Use sdk to create a ClientProvider () -// 3. From client provider create resmgmt Client -// You can then use this .Client to call for specific functionalities -func NewFabricResmgmtClient(orgName, userName string, opts ...resmgmt.ClientOption) (*fabricResmgtmClient, error) { - sdk, err := GetSDK() - if err != nil { - return nil, err - } - - // Create ClientProvider - clientProvider := sdk.CreateClientContext(fabsdk.WithOrg(orgName), fabsdk.WithUser(userName)) - - // Resource management client is responsible for managing channels (create/update channel) - // Supply user that has privileges to create channel - resMgmtClient, err := resmgmt.New(clientProvider, opts...) - if err != nil { - return nil, err - } - - return &fabricResmgtmClient{ - Provider: clientProvider, - Client: resMgmtClient, - }, nil -} - -// Returns a client which has channel transaction capabilities -// These are, but not limited to: Execute, Query, Invoke cc... -// -// Function works like this: -// 1. Get sdk -// 2. Use sdk to create a ChannelProvider () -// 3. From channel provider create channel Client -// You can then use this .Client to call for specific functionalities -func NewFabricChClient(channelName, userName, orgName string) (*fabricChannelClient, error) { - sdk, err := GetSDK() - if err != nil { - return nil, err - } - - // Create Channel Provider - chProvider := sdk.CreateChannelContext(channelName, fabsdk.WithUser(userName), fabsdk.WithOrg(orgName)) - - // Create Channel's chClient - chClient, err := channel.New(chProvider) - if err != nil { - return nil, err - } - - return &fabricChannelClient{ - Provider: chProvider, - Client: chClient, - }, nil -} - -// Returns a client which can query a channel's underlying ledger, -// such as QueryBlock and QueryConfig -// -// Function works like this: -// 1. Get sdk -// 2. Use sdk to create a ChannelProvider () -// 3. From channel provider create ledger Client -// You can then use this .Client to call for specific functionalities -func NewFabricLedgerClient(channelName, user, orgName string) (*fabricLedgerClient, error) { - sdk, err := GetSDK() - if err != nil { - return nil, err - } - - // Create Channel Provider - chProvider := sdk.CreateChannelContext(channelName, fabsdk.WithUser(user), fabsdk.WithOrg(orgName)) - // chProvider := sdk.CreateChannelContext(channelName, ) - // Create Channel's chClient - ledgerClient, err := ledger.New(chProvider) - if err != nil { - return nil, err - } - - return &fabricLedgerClient{ - Provider: chProvider, - Client: ledgerClient, - }, nil -} diff --git a/samples/application/ccapi/config/configsdk-org.yaml b/samples/application/ccapi/config/configsdk-org.yaml deleted file mode 100644 index 359c5d99a..000000000 --- a/samples/application/ccapi/config/configsdk-org.yaml +++ /dev/null @@ -1,220 +0,0 @@ -version: 1.0.0 - -# -# The client section used by GO SDK. -# -client: - # Which organization does this application instance belong to? The value must be the name of an org - # defined under "organizations" - organization: org - logging: - # Develope can using debug to get more information - # level: debug - level: info - cryptoconfig: - path: "/fabric/organizations" - # Some SDKs support pluggable KV stores, the properties under "credentialStore" - # are implementation specific - credentialStore: - # [Optional]. Used by user store. Not needed if all credentials are embedded in configuration - # and enrollments are performed elswhere. - path: "/tmp/examplestore" - - # [Optional] BCCSP config for the client. Used by GO SDK. - BCCSP: - security: - enabled: true - default: - provider: "SW" - hashAlgorithm: "SHA2" - softVerify: true - level: 256 - - tlsCerts: - # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false - systemCertPool: true - # [Optional]. Client key and cert for TLS handshake with peers and orderers - client: - # 使用byfn中Admin@org的证书 - keyfile: /fabric/organizations/peerOrganizations/org.example.com/users/Admin@org.example.com/tls/client.key - certfile: /fabric/organizations/peerOrganizations/org.example.com/users/Admin@org.example.com/tls/client.crt - cacertfile: /fabric/organizations/peerOrganizations/org.example.com/users/Admin@org.example.com/tls/ca.crt - -################################## General part ################################## - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mainchannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - # deprecated: not recommended, to override any orderer configuration items, entity matchers should be used. - # orderers: - # - orderer.example.com - - # 不要缺少当前channel的orderer节点 - # orderers: - # - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - # [Optional]. The application can use these options to perform channel operations like retrieving channel - # config etc. - policies: - #[Optional] options for retrieving channel configuration blocks - queryChannelConfig: - #[Optional] min number of success responses (from targets/peers) - minResponses: 1 - #[Optional] channel config will be retrieved for these number of random targets - maxTargets: 1 - #[Optional] retry options for query config block - retryOpts: - #[Optional] number of retry attempts - attempts: 5 - #[Optional] the back off interval for the first retry attempt - initialBackoff: 500ms - #[Optional] the maximum back off interval for any retry attempt - maxBackoff: 5s - #[Optional] he factor by which the initial back off period is exponentially incremented - backoffFactor: 2.0 - -# -# list of participating organizations in this network -# -organizations: - org: - mspid: orgMSP - # set msp files path (this path is relative to client.cryptoConfig defined above) - cryptoPath: peerOrganizations/org.example.com/users/{username}@org.example.com/msp - - # Add peers for org - peers: - - peer0.org.example.com - - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - - # Orderer Org name - OrdererOrg: - # Membership Service Provider ID for this organization - mspID: OrdererMSP - cryptoPath: ordererOrganizations/example.com/users/Admin@example.com/msp - peers: - - orderer.example.com - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org.example.com: - # this URL is used to send endorsement and query requests - # [Optional] Default: Infer from hostname - # url: grpcs://peer0.org.example.com:7051 - url: grpcs://peer0.org.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /fabric/organizations/peerOrganizations/org.example.com/tlsca/tlsca.org.example.com-cert.pem - - - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -entitymatchers: - peer: - - pattern: (\w*)peer0.org.example.com(\w*) - urlsubstitutionexp: grpcs://peer0.org.example.com:7051 - ssltargetoverrideurlsubstitutionexp: peer0.org.example.com - mappedhost: peer0.org.example.com - - orderer: - - pattern: (\w*)orderer.example.com(\w*) - urlsubstitutionexp: orderer.example.com:7050 - ssltargetoverrideurlsubstitutionexp: orderer.example.com - mappedhost: orderer.example.com diff --git a/samples/application/ccapi/config/configsdk-org1.yaml b/samples/application/ccapi/config/configsdk-org1.yaml deleted file mode 100644 index 93080f20d..000000000 --- a/samples/application/ccapi/config/configsdk-org1.yaml +++ /dev/null @@ -1,220 +0,0 @@ -version: 1.0.0 - -# -# The client section used by GO SDK. -# -client: - # Which organization does this application instance belong to? The value must be the name of an org - # defined under "organizations" - organization: org1 - logging: - # Develope can using debug to get more information - # level: debug - level: info - cryptoconfig: - path: "/fabric/organizations" - # Some SDKs support pluggable KV stores, the properties under "credentialStore" - # are implementation specific - credentialStore: - # [Optional]. Used by user store. Not needed if all credentials are embedded in configuration - # and enrollments are performed elswhere. - path: "/tmp/examplestore" - - # [Optional] BCCSP config for the client. Used by GO SDK. - BCCSP: - security: - enabled: true - default: - provider: "SW" - hashAlgorithm: "SHA2" - softVerify: true - level: 256 - - tlsCerts: - # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false - systemCertPool: false - # [Optional]. Client key and cert for TLS handshake with peers and orderers - client: - # 使用byfn中Admin@org1的证书 - keyfile: /fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/client.key - certfile: /fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/client.cert - cacertfile: /fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/tls/ca.crt - -################################## General part ################################## - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mychannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org1" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - # deprecated: not recommended, to override any orderer configuration items, entity matchers should be used. - # orderers: - # - orderer.example.com - - # 不要缺少当前channel的orderer节点 - # orderers: - # - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org1.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - # [Optional]. The application can use these options to perform channel operations like retrieving channel - # config etc. - policies: - #[Optional] options for retrieving channel configuration blocks - queryChannelConfig: - #[Optional] min number of success responses (from targets/peers) - minResponses: 1 - #[Optional] channel config will be retrieved for these number of random targets - maxTargets: 1 - #[Optional] retry options for query config block - retryOpts: - #[Optional] number of retry attempts - attempts: 5 - #[Optional] the back off interval for the first retry attempt - initialBackoff: 500ms - #[Optional] the maximum back off interval for any retry attempt - maxBackoff: 5s - #[Optional] he factor by which the initial back off period is exponentially incremented - backoffFactor: 2.0 - -# -# list of participating organizations in this network -# -organizations: - org1: - mspid: org1MSP - # set msp files path (this path is relative to client.cryptoConfig defined above) - cryptoPath: peerOrganizations/org1.example.com/users/{username}@org1.example.com/msp - - # Add peers for org1 - peers: - - peer0.org1.example.com - - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - - # Orderer Org name - OrdererOrg: - # Membership Service Provider ID for this organization - mspID: OrdererMSP - cryptoPath: ordererOrganizations/example.com/users/Admin@example.com/msp - peers: - - orderer.example.com - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org1.example.com: - # this URL is used to send endorsement and query requests - # [Optional] Default: Infer from hostname - # url: grpcs://peer0.org1.example.com:7051 - url: grpcs://peer0.org1.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org1.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /fabric/organizations/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem - - - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -entitymatchers: - peer: - - pattern: (\w*)peer0.org1.example.com(\w*) - urlsubstitutionexp: grpcs://peer0.org1.example.com:7051 - ssltargetoverrideurlsubstitutionexp: peer0.org1.example.com - mappedhost: peer0.org1.example.com - - orderer: - - pattern: (\w*)orderer.example.com(\w*) - urlsubstitutionexp: orderer.example.com:7050 - ssltargetoverrideurlsubstitutionexp: orderer.example.com - mappedhost: orderer.example.com diff --git a/samples/application/ccapi/config/configsdk-org2.yaml b/samples/application/ccapi/config/configsdk-org2.yaml deleted file mode 100644 index 6521bf539..000000000 --- a/samples/application/ccapi/config/configsdk-org2.yaml +++ /dev/null @@ -1,220 +0,0 @@ -version: 1.0.0 - -# -# The client section used by GO SDK. -# -client: - # Which organization does this application instance belong to? The value must be the name of an org - # defined under "organizations" - organization: org2 - logging: - # Develope can using debug to get more information - # level: debug - level: info - cryptoconfig: - path: "/fabric/organizations" - # Some SDKs support pluggable KV stores, the properties under "credentialStore" - # are implementation specific - credentialStore: - # [Optional]. Used by user store. Not needed if all credentials are embedded in configuration - # and enrollments are performed elswhere. - path: "/tmp/examplestore" - - # [Optional] BCCSP config for the client. Used by GO SDK. - BCCSP: - security: - enabled: true - default: - provider: "SW" - hashAlgorithm: "SHA2" - softVerify: true - level: 256 - - tlsCerts: - # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false - systemCertPool: false - # [Optional]. Client key and cert for TLS handshake with peers and orderers - client: - # 使用byfn中Admin@org2的证书 - keyfile: /fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/tls/client.key - certfile: /fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/tls/client.cert - cacertfile: /fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/tls/ca.crt - -################################## General part ################################## - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mychannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org2" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - # deprecated: not recommended, to override any orderer configuration items, entity matchers should be used. - # orderers: - # - orderer.example.com - - # 不要缺少当前channel的orderer节点 - # orderers: - # - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org2.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - # [Optional]. The application can use these options to perform channel operations like retrieving channel - # config etc. - policies: - #[Optional] options for retrieving channel configuration blocks - queryChannelConfig: - #[Optional] min number of success responses (from targets/peers) - minResponses: 1 - #[Optional] channel config will be retrieved for these number of random targets - maxTargets: 1 - #[Optional] retry options for query config block - retryOpts: - #[Optional] number of retry attempts - attempts: 5 - #[Optional] the back off interval for the first retry attempt - initialBackoff: 500ms - #[Optional] the maximum back off interval for any retry attempt - maxBackoff: 5s - #[Optional] he factor by which the initial back off period is exponentially incremented - backoffFactor: 2.0 - -# -# list of participating organizations in this network -# -organizations: - org2: - mspid: org2MSP - # set msp files path (this path is relative to client.cryptoConfig defined above) - cryptoPath: peerOrganizations/org2.example.com/users/{username}@org2.example.com/msp - - # Add peers for org2 - peers: - - peer0.org2.example.com - - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - - # Orderer Org name - OrdererOrg: - # Membership Service Provider ID for this organization - mspID: OrdererMSP - cryptoPath: ordererOrganizations/example.com/users/Admin@example.com/msp - peers: - - orderer.example.com - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org2.example.com: - # this URL is used to send endorsement and query requests - # [Optional] Default: Infer from hostname - # url: grpcs://peer0.org2.example.com:7051 - url: grpcs://peer0.org2.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org2.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /fabric/organizations/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem - - - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -entitymatchers: - peer: - - pattern: (\w*)peer0.org2.example.com(\w*) - urlsubstitutionexp: grpcs://peer0.org2.example.com:7051 - ssltargetoverrideurlsubstitutionexp: peer0.org2.example.com - mappedhost: peer0.org2.example.com - - orderer: - - pattern: (\w*)orderer.example.com(\w*) - urlsubstitutionexp: orderer.example.com:7050 - ssltargetoverrideurlsubstitutionexp: orderer.example.com - mappedhost: orderer.example.com diff --git a/samples/application/ccapi/config/configsdk-org3.yaml b/samples/application/ccapi/config/configsdk-org3.yaml deleted file mode 100644 index 41dc0e1fa..000000000 --- a/samples/application/ccapi/config/configsdk-org3.yaml +++ /dev/null @@ -1,220 +0,0 @@ -version: 1.0.0 - -# -# The client section used by GO SDK. -# -client: - # Which organization does this application instance belong to? The value must be the name of an org - # defined under "organizations" - organization: org3 - logging: - # Develope can using debug to get more information - # level: debug - level: info - cryptoconfig: - path: "/fabric/organizations" - # Some SDKs support pluggable KV stores, the properties under "credentialStore" - # are implementation specific - credentialStore: - # [Optional]. Used by user store. Not needed if all credentials are embedded in configuration - # and enrollments are performed elswhere. - path: "/tmp/examplestore" - - # [Optional] BCCSP config for the client. Used by GO SDK. - BCCSP: - security: - enabled: true - default: - provider: "SW" - hashAlgorithm: "SHA2" - softVerify: true - level: 256 - - tlsCerts: - # [Optional]. Use system certificate pool when connecting to peers, orderers (for negotiating TLS) Default: false - systemCertPool: true - # [Optional]. Client key and cert for TLS handshake with peers and orderers - client: - # 使用byfn中Admin@org3的证书 - keyfile: /fabric/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/tls/client.key - certfile: /fabric/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/tls/client.cert - cacertfile: /fabric/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/tls/ca.crt - -################################## General part ################################## - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mainchannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org3" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - # deprecated: not recommended, to override any orderer configuration items, entity matchers should be used. - # orderers: - # - orderer.example.com - - # 不要缺少当前channel的orderer节点 - # orderers: - # - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org3.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - # [Optional]. The application can use these options to perform channel operations like retrieving channel - # config etc. - policies: - #[Optional] options for retrieving channel configuration blocks - queryChannelConfig: - #[Optional] min number of success responses (from targets/peers) - minResponses: 1 - #[Optional] channel config will be retrieved for these number of random targets - maxTargets: 1 - #[Optional] retry options for query config block - retryOpts: - #[Optional] number of retry attempts - attempts: 5 - #[Optional] the back off interval for the first retry attempt - initialBackoff: 500ms - #[Optional] the maximum back off interval for any retry attempt - maxBackoff: 5s - #[Optional] he factor by which the initial back off period is exponentially incremented - backoffFactor: 2.0 - -# -# list of participating organizations in this network -# -organizations: - org3: - mspid: org3MSP - # set msp files path (this path is relative to client.cryptoConfig defined above) - cryptoPath: peerOrganizations/org3.example.com/users/{username}@org3.example.com/msp - - # Add peers for org3 - peers: - - peer0.org3.example.com - - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - - # Orderer Org name - OrdererOrg: - # Membership Service Provider ID for this organization - mspID: OrdererMSP - cryptoPath: ordererOrganizations/example.com/users/Admin@example.com/msp - peers: - - orderer.example.com - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org3.example.com: - # this URL is used to send endorsement and query requests - # [Optional] Default: Infer from hostname - # url: grpcs://peer0.org3.example.com:7051 - url: grpcs://peer0.org3.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org3.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /fabric/organizations/peerOrganizations/org3.example.com/tlsca/tlsca.org3.example.com-cert.pem - - - orderer.example.com: - # [Optional] Default: Infer from hostname - url: grpcs://orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - - #will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - # Replace to orderer cert path - path: /fabric/organizations/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -entitymatchers: - peer: - - pattern: (\w*)peer0.org3.example.com(\w*) - urlsubstitutionexp: grpcs://peer0.org3.example.com:7051 - ssltargetoverrideurlsubstitutionexp: peer0.org3.example.com - mappedhost: peer0.org3.example.com - - orderer: - - pattern: (\w*)orderer.example.com(\w*) - urlsubstitutionexp: orderer.example.com:7050 - ssltargetoverrideurlsubstitutionexp: orderer.example.com - mappedhost: orderer.example.com diff --git a/samples/application/ccapi/docs/docs.go b/samples/application/ccapi/docs/docs.go deleted file mode 100644 index 94bb251e0..000000000 --- a/samples/application/ccapi/docs/docs.go +++ /dev/null @@ -1,35 +0,0 @@ -// Code generated by swaggo/swag. DO NOT EDIT. - -package docs - -import "github.com/swaggo/swag" - -const docTemplate = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": {} -}` - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = &swag.Spec{ - Version: "", - Host: "", - BasePath: "", - Schemes: []string{}, - Title: "", - Description: "", - InfoInstanceName: "swagger", - SwaggerTemplate: docTemplate, -} - -func init() { - swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) -} diff --git a/samples/application/ccapi/docs/swagger.yaml b/samples/application/ccapi/docs/swagger.yaml deleted file mode 100644 index ca2113ba9..000000000 --- a/samples/application/ccapi/docs/swagger.yaml +++ /dev/null @@ -1,1087 +0,0 @@ -openapi: 3.0.0 -info: - description: Documentation of the Chaincode API. This API is used to interact with the chaincode through the Gateway service. - version: "1.0" - title: CC Tools Demo -servers: - - url: /api -tags: - - name: Basic Operations - - name: Select Channel and Chaincode - - name: Blockchain -components: - securitySchemes: - basicAuth: - type: "http" - scheme: "basic" -paths: - /invoke/{txName}: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Executes transaction txName and writes the result to the blockchain. - parameters: - - in: path - name: txName - schema: - type: string - required: true - description: Name of the transaction to be executed. - requestBody: - description: The request body must match the definition of the transaction arguments. - content: - application/json: - schema: - type: object - responses: - "200": - description: OK - "4XX": - description: Bad Request - 5XX: - description: Internal error - /query/{txName}: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Executes transaction txName and returns only the result, without writing it to the blockchain. - parameters: - - in: path - name: txName - schema: - type: string - required: true - description: Name of the transaction to be executed. - requestBody: - description: The request body must match the definition of the transaction arguments. - content: - application/json: - schema: - type: object - responses: - "200": - description: OK - "4XX": - description: Bad Request - 5XX: - description: Internal error - - /query/getHeader: - get: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Retrieves information about the chaincode. - responses: - "200": - description: OK - 5XX: - description: Internal error. - - /query/getTx: - get: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Requests the list of defined transactions. - responses: - "200": - description: OK - 5XX: - description: Internal error - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Gets the description of a specific transaction. - requestBody: - description: The txName field must contain the name of a transaction defined by the chaincode. - content: - application/json: - schema: - txName: - type: string - examples: - getTx: - value: - txName: getTx - responses: - "200": - description: OK - "400": - description: Bad Request - "404": - description: Transaction not found - 5XX: - description: Internal error - - /query/getSchema: - get: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Searches the list of existing assets. - responses: - "200": - description: OK - 5XX: - description: Internal error - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Gets the description of a specific asset type. - requestBody: - description: The assetType must contain an asset type defined by the chaincode. - content: - application/json: - schema: - assetType: - type: string - examples: - person: - value: - assetType: person - responses: - "200": - description: OK - "400": - description: Bad Request - "404": - description: Asset type not found - 5XX: - description: Internal error - - /invoke/createAsset: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Create asset on the blockchain - requestBody: - description: The asset must be an array of objects. Each object must contain the asset type in the @assetType field and the asset data in the other fields. - content: - application/json: - schema: - type: object - properties: - asset: - type: array - items: - description: Any asset type defined by the chaincode. Check via getSchema. - type: object - examples: - person: - summary: "Create person" - value: - asset: - - "@assetType": person - name: "Maria" - id: "318.207.920-48" - responses: - "200": - description: OK - "400": - description: Bad format - "409": - description: Asset already exists - 5XX: - description: Internal error - - /query/readAsset: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: "Reads an asset from the blockchain using its primary key." - requestBody: - content: - application/json: - schema: - type: object - properties: - key: - type: object - examples: - person: - summary: person - value: - key: - "@assetType": person - id: "318.207.920-48" - responses: - "200": - description: OK - "404": - description: Asset not found - 5XX: - description: Internal error - - /query/readAssetHistory: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: "Reads the history of an asset from the blockchain using its primary key." - requestBody: - content: - application/json: - schema: - type: object - properties: - key: - type: object - examples: - person: - summary: person - value: - key: - "@assetType": person - id: "318.207.920-48" - responses: - "200": - description: OK - "404": - description: Asset not found - 5XX: - description: Internal error - - /query/search: - post: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Searches the blockchain world state using CouchDB rich queries - description: "Query JSON as defined by CouchDB docs: https://docs.couchdb.org/en/stable/api/database/find.html" - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - query: - selector: - type: object - limit: - type: integer - bookmark: - type: string - examples: - personAll: - summary: Get all assets of type person - value: - query: - selector: - "@assetType": person - personFirst10: - summary: Get first 10 assets of type person - value: - query: - selector: - "@assetType": person - limit: 10 - bookmark: "" - person10to20: - summary: Get assets 10-20 of type person - value: - query: - selector: - "@assetType": person - limit: 10 - bookmark: "g1AAAACGeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYprF6QWFefnWaVaGBmbWCan6BqZJ6fpmqalWOgmGSWZ65qbWFommpkZWCYlW4KM4IAZQarmLAD0pSXP" - responses: - "200": - description: OK - "400": - description: Bad format - 5XX: - description: Internal error - - /invoke/updateAsset: - put: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Updates an existing asset - requestBody: - content: - application/json: - schema: - type: object - properties: - "@assetType": - type: string - examples: - updateHeight: - summary: "Change person height" - value: - update: - "@assetType": "person" - name: "Maria" - height: 1.66 - description: The asset must contain the primary key of the asset and the fields to be updated. - required: true - responses: - "200": - description: OK - "400": - description: Bad format - "404": - description: Asset not found - 5XX: - description: Internal error - - /invoke/deleteAsset: - delete: - tags: - - Basic Operations - security: - - basicAuth: [] - summary: Deletes an existing asset - requestBody: - content: - application/json: - schema: - type: object - properties: - "@assetType": - type: string - examples: - deletePerson: - summary: 'Delete person with name "Maria"' - value: - key: - "@assetType": person - id: "318.207.920-48" - description: The asset must contain the primary key of the asset. - required: true - responses: - "200": - description: OK - "400": - description: Bad format - "404": - description: Asset not found - 5XX: - description: Internal error - /{channelName}/{chaincodeName}/invoke/{txName}: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Executes transaction txName and writes the result to the blockchain. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - - in: path - name: txName - schema: - type: string - required: true - description: Name of the transaction to be executed. - requestBody: - description: The request body must match the definition of the transaction arguments. - content: - application/json: - schema: - type: object - responses: - "200": - description: OK - "4XX": - description: Bad Request - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/{txName}: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Executes transaction txName and returns only the result, without writing it to the blockchain. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - - in: path - name: txName - schema: - type: string - required: true - description: Name of the transaction to be executed. - requestBody: - description: The request body must match the definition of the transaction arguments. - content: - application/json: - schema: - type: object - responses: - "200": - description: OK - "4XX": - description: Bad Request - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/getHeader: - get: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Retrieves information about the chaincode. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - responses: - "200": - description: OK - 5XX: - description: Internal error. - - /{channelName}/{chaincodeName}/query/getTx: - get: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Requests the list of defined transactions. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - responses: - "200": - description: OK - 5XX: - description: Internal error - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Gets the description of a specific transaction. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - description: The txName field must contain the name of a transaction defined by the chaincode. - content: - application/json: - schema: - txName: - type: string - examples: - getTx: - value: - txName: getTx - responses: - "200": - description: OK - "400": - description: Bad Request - "404": - description: Transaction not found - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/getSchema: - get: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Searches the list of existing assets. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - responses: - "200": - description: OK - 5XX: - description: Internal error - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Gets the description of a specific asset type. - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - description: The assetType must contain an asset type defined by the chaincode. - content: - application/json: - schema: - assetType: - type: string - examples: - person: - value: - assetType: person - responses: - "200": - description: OK - "400": - description: Bad Request - "404": - description: Asset type not found - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/invoke/createAsset: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Create asset on the blockchain - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - description: The asset must be an array of objects. Each object must contain the asset type in the @assetType field and the asset data in the other fields. - content: - application/json: - schema: - type: object - properties: - asset: - type: array - items: - description: Any asset type defined by the chaincode. Check via getSchema. - type: object - examples: - person: - summary: "Create person" - value: - asset: - - "@assetType": person - name: "Maria" - id: "318.207.920-48" - responses: - "200": - description: OK - "400": - description: Bad format - "409": - description: Asset already exists - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/readAsset: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: "Reads an asset from the blockchain using its primary key." - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - content: - application/json: - schema: - type: object - properties: - key: - type: object - examples: - person: - summary: person - value: - key: - "@assetType": person - id: "318.207.920-48" - responses: - "200": - description: OK - "404": - description: Asset not found - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/readAssetHistory: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: "Reads the history of an asset from the blockchain using its primary key." - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - content: - application/json: - schema: - type: object - properties: - key: - type: object - examples: - person: - summary: person - value: - key: - "@assetType": person - id: "318.207.920-48" - responses: - "200": - description: OK - "404": - description: Asset not found - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/query/search: - post: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Searches the blockchain world state using CouchDB rich queries - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - description: "Query JSON as defined by CouchDB docs: https://docs.couchdb.org/en/stable/api/database/find.html" - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - query: - selector: - type: object - limit: - type: integer - bookmark: - type: string - examples: - personAll: - summary: Get all assets of type person - value: - query: - selector: - "@assetType": person - personFirst10: - summary: Get first 10 assets of type person - value: - query: - selector: - "@assetType": person - limit: 10 - bookmark: "" - person10to20: - summary: Get assets 10-20 of type person - value: - query: - selector: - "@assetType": person - limit: 10 - bookmark: "g1AAAACGeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYprF6QWFefnWaVaGBmbWCan6BqZJ6fpmqalWOgmGSWZ65qbWFommpkZWCYlW4KM4IAZQarmLAD0pSXP" - responses: - "200": - description: OK - "400": - description: Bad format - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/invoke/updateAsset: - put: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Updates an existing asset - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - content: - application/json: - schema: - type: object - properties: - "@assetType": - type: string - examples: - updateHeight: - summary: "Change person height" - value: - update: - "@assetType": "person" - name: "Maria" - height: 1.66 - description: The asset must contain the primary key of the asset and the fields to be updated. - required: true - responses: - "200": - description: OK - "400": - description: Bad format - "404": - description: Asset not found - 5XX: - description: Internal error - - /{channelName}/{chaincodeName}/invoke/deleteAsset: - delete: - tags: - - Select Channel and Chaincode - security: - - basicAuth: [] - summary: Deletes an existing asset - parameters: - - in: path - name: channelName - schema: - type: string - required: true - description: Name of the channel. - - in: path - name: chaincodeName - schema: - type: string - required: true - description: Name of the chaincode in channel. - requestBody: - content: - application/json: - schema: - type: object - properties: - "@assetType": - type: string - examples: - deletePerson: - summary: 'Delete person with name "Maria"' - value: - key: - "@assetType": person - id: "318.207.920-48" - description: The asset must contain the primary key of the asset. - required: true - responses: - "200": - description: OK - "400": - description: Bad format - "404": - description: Asset not found - 5XX: - description: Internal error - /{channelName}/qscc/getBlockByNumber: - get: - summary: Get block by number - description: Retrieves a block by its number from the specified channel. - parameters: - - name: channelName - in: path - required: true - schema: - type: string - example: mainchannel - - name: number - in: query - required: true - schema: - type: integer - example: 10 - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - '400': - description: Bad request - '404': - description: Block not found - tags: - - Blockchain - security: - - basicAuth: [] - consumes: - - application/json - produces: - - application/json - /{channelName}/qscc/getBlockByHash: - get: - summary: Get block by hash - description: Retrieves a block by its hash from the specified channel. - tags: - - Blockchain - security: - - basicAuth: [] - parameters: - - name: channelName - in: path - required: true - schema: - type: string - example: mainchannel - description: Name of the channel. - - name: hash - in: query - required: true - schema: - type: string - example: dbd2b14fb3d61b7aeac3add76f99cd9b47850c7c95ca5e489696a6b543fc6b2d - description: The hash of the block to be retrieved. - responses: - "200": - description: Successful response - content: - application/json: - schema: - type: object - "400": - description: Bad request - "404": - description: Block not found - "500": - description: Internal server error - /{channelName}/qscc/getChainInfo: - get: - summary: Get chain info - description: Retrieves chain information from the specified channel. - parameters: - - name: channelName - in: path - required: true - schema: - type: string - example: mainchannel - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - '400': - description: Bad request - '404': - description: Chain info not found - tags: - - Blockchain - security: - - basicAuth: [] - consumes: - - application/json - produces: - - application/json - /{channelName}/qscc/getTransactionByID: - get: - summary: Get transaction by ID - description: Retrieves a transaction by its ID from the specified channel. - parameters: - - name: channelName - in: path - required: true - schema: - type: string - example: mainchannel - - name: txid - in: query - required: true - schema: - type: string - example: 41675014bf3205b68e2620a802247f77adc730c77426885b15eebc28add6a414 - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - '400': - description: Bad request - '404': - description: Transaction not found - tags: - - Blockchain - security: - - basicAuth: [] - consumes: - - application/json - produces: - - application/json - /{channelName}/qscc/getBlockByTxID: - get: - summary: Get block by transaction ID - description: Retrieves a block by its transaction ID from the specified channel. - parameters: - - name: channelName - in: path - required: true - schema: - type: string - example: mainchannel - - name: txid - in: query - required: true - schema: - type: string - example: 41675014bf3205b68e2620a802247f77adc730c77426885b15eebc28add6a414 - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - '400': - description: Bad request - '404': - description: Block not found - tags: - - Blockchain - security: - - basicAuth: [] - consumes: - - application/json - produces: - - application/json \ No newline at end of file diff --git a/samples/application/ccapi/fpc-docker-compose.yaml b/samples/application/ccapi/fpc-docker-compose.yaml deleted file mode 100644 index 4aea2bbcd..000000000 --- a/samples/application/ccapi/fpc-docker-compose.yaml +++ /dev/null @@ -1,83 +0,0 @@ -version: "2" -services: - ccapi.org1.example.com: - build: - dockerfile: Dockerfile - context: . - ports: - - 80:80 - volumes: - - ./:/rest-server - - /src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations:/fabric/organizations - - /src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations/:/project/src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations/ - logging: - options: - max-size: 50m - environment: - - SDK_PATH=./config/configsdk-org1.yaml - - USER=Admin - - ORG=org1 - - DOMAIN=example.com - - CHANNEL=mychannel - - CCNAME=cc-tools-demo - - FABRIC_GATEWAY_ENDPOINT=peer0.org1.example.com:7051 - - FABRIC_GATEWAY_NAME=peer0.org1.example.com - - GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn - - FPC_ENABLED=true - - SGX_MODE=SIM - - CORE_PEER_ADDRESS=peer0.org1.example.com:7051 - - CORE_PEER_ID=peer0.org1.example.com - - CORE_PEER_LOCALMSPID=Org1MSP - - CORE_PEER_MSPCONFIGPATH=/fabric/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - - CORE_PEER_TLS_CERT_FILE=/fabric/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt - - CORE_PEER_TLS_ENABLED="true" - - CORE_PEER_TLS_KEY_FILE=/fabric/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key - - CORE_PEER_TLS_ROOTCERT_FILE=/fabric/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt - - ORDERER_CA=/fabric/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem - - GATEWAY_CONFIG=/fabric/organizations/peerOrganizations/org1.example.com/external-connection-org1.yaml - working_dir: /rest-server - container_name: ccapi.org1.example.com - networks: - - fabric_test - ccapi.org2.example.com: - build: - dockerfile: Dockerfile - context: . - ports: - - 980:80 - volumes: - - ./:/rest-server - - /src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations:/fabric/organizations - - /src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations/:/project/src/github.com/hyperledger/fabric-private-chaincode/samples/deployment/test-network/fabric-samples/test-network/organizations/ - logging: - options: - max-size: 50m - environment: - - SDK_PATH=./config/configsdk-org2.yaml - - USER=Admin - - ORG=org2 - - DOMAIN=example.com - - CHANNEL=mychannel - - CCNAME=cc-tools-demo - - FABRIC_GATEWAY_ENDPOINT=peer0.org2.example.com:7051 - - FABRIC_GATEWAY_NAME=peer0.org2.example.com - - GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn - - FPC_MODE=true - - SGX_MODE=SIM - - CORE_PEER_ADDRESS=peer0.org2.example.com:7051 - - CORE_PEER_ID=peer0.org2.example.com - - CORE_PEER_LOCALMSPID=Org2MSP - - CORE_PEER_MSPCONFIGPATH=/fabric/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp - - CORE_PEER_TLS_CERT_FILE=/fabric/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt - - CORE_PEER_TLS_ENABLED="true" - - CORE_PEER_TLS_KEY_FILE=/fabric/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key - - CORE_PEER_TLS_ROOTCERT_FILE=/fabric/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt - - ORDERER_CA=/fabric/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem - - GATEWAY_CONFIG=/fabric/organizations/peerOrganizations/org2.example.com/external-connection-org2.yaml - working_dir: /rest-server - container_name: ccapi.org2.example.com - networks: - - fabric_test -networks: - fabric_test: - external: true diff --git a/samples/application/ccapi/fpcUtils/config.go b/samples/application/ccapi/fpcUtils/config.go deleted file mode 100644 index 397a04855..000000000 --- a/samples/application/ccapi/fpcUtils/config.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package fpcUtils - -type Config struct { - CorePeerAddress string - CorePeerId string - CorePeerLocalMSPID string - CorePeerMSPConfigPath string - CorePeerTLSCertFile string - CorePeerTLSEnabled bool - CorePeerTLSKeyFile string - CorePeerTLSRootCertFile string - OrdererCA string - FpcPath string - ChaincodeId string - ChannelId string - GatewayConfigPath string -} diff --git a/samples/application/ccapi/fpcUtils/connections.go b/samples/application/ccapi/fpcUtils/connections.go deleted file mode 100644 index 7bc89b7d8..000000000 --- a/samples/application/ccapi/fpcUtils/connections.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package fpcUtils - -import ( - "os" - - "gopkg.in/yaml.v2" -) - -type Connections struct { - Peers map[string]struct { - Url string - } - - Orderers map[string]struct { - Url string - } -} - -func NewConnections(path string) (*Connections, error) { - connections := &Connections{} - - file, err := os.Open(path) - if err != nil { - return nil, err - } - defer file.Close() - - d := yaml.NewDecoder(file) - - if err := d.Decode(&connections); err != nil { - return nil, err - } - - return connections, nil -} diff --git a/samples/application/ccapi/fpcUtils/fpcadmin.go b/samples/application/ccapi/fpcUtils/fpcadmin.go deleted file mode 100644 index 484cd51dc..000000000 --- a/samples/application/ccapi/fpcUtils/fpcadmin.go +++ /dev/null @@ -1,89 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package fpcUtils - -import ( - "fmt" - "path/filepath" - - fpcmgmt "github.com/hyperledger/fabric-private-chaincode/client_sdk/go/pkg/client/resmgmt" - "github.com/hyperledger/fabric-private-chaincode/client_sdk/go/pkg/sgx" - "github.com/hyperledger/fabric-sdk-go/pkg/client/resmgmt" - "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry" - cfg "github.com/hyperledger/fabric-sdk-go/pkg/core/config" - "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" -) - -type Admin struct { - sdk *fabsdk.FabricSDK - client *fpcmgmt.Client - config *Config - connections *Connections -} - -func (a *Admin) Close() { - a.sdk.Close() -} - -func NewAdmin(config *Config) *Admin { - connections, err := NewConnections(filepath.Clean(config.GatewayConfigPath)) - if err != nil { - logger.Fatalf("failed to parse connections: %v", err) - } - - sdk, err := fabsdk.New(cfg.FromFile(filepath.Clean(config.GatewayConfigPath))) - if err != nil { - logger.Fatalf("failed to create sdk: %v", err) - } - //defer sdk.Close() - - orgAdmin := "Admin" - orgName := "org1" - adminContext := sdk.Context(fabsdk.WithUser(orgAdmin), fabsdk.WithOrg(orgName)) - - client, err := fpcmgmt.New(adminContext) - if err != nil { - logger.Fatalf("failed to create context: %v", err) - } - logger.Infof("I AM HERE 1") - return &Admin{sdk: sdk, client: client, config: config, connections: connections} -} - -func (a *Admin) InitEnclave(targetPeer string) error { - - logger.Infof("--> Collection attestation params ") - attestationParams, err := sgx.CreateAttestationParamsFromEnvironment() - if err != nil { - logger.Errorf("failed to load attestation params from environment: %v", err) - return fmt.Errorf("failed to load attestation params from environment: %v", err) - } - logger.Infof("I AM HERE 2") - - initReq := fpcmgmt.LifecycleInitEnclaveRequest{ - ChaincodeID: a.config.ChaincodeId, - EnclavePeerEndpoint: targetPeer, // define the peer where we wanna init our enclave - AttestationParams: attestationParams, - } - logger.Infof("I AM HERE 3") - - peers := []string{"peer0-org1", "peer0-org2", "peer0-org3"} - orderer := "orderer0" - - logger.Infof("--> LifecycleInitEnclave ") - _, err = a.client.LifecycleInitEnclave(a.config.ChannelId, initReq, - // Note that these options are currently ignored by our implementation - resmgmt.WithRetry(retry.DefaultResMgmtOpts), - resmgmt.WithTargetEndpoints(peers...), // peers that are responsible for enclave registration - resmgmt.WithOrdererEndpoint(orderer), - ) - - if err != nil { - return err - } - - return nil -} diff --git a/samples/application/ccapi/fpcUtils/fpcclient.go b/samples/application/ccapi/fpcUtils/fpcclient.go deleted file mode 100644 index 934ca3e79..000000000 --- a/samples/application/ccapi/fpcUtils/fpcclient.go +++ /dev/null @@ -1,124 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package fpcUtils - -import ( - "fmt" - "os" - "path/filepath" - "strings" - - fpc "github.com/hyperledger/fabric-private-chaincode/client_sdk/go/pkg/gateway" - cfg "github.com/hyperledger/fabric-sdk-go/pkg/core/config" - "github.com/hyperledger/fabric-sdk-go/pkg/gateway" - "github.com/pkg/errors" -) - -type Client struct { - contract fpc.Contract -} - -func NewClient(config *Config) *Client { - return &Client{contract: newContract(config)} -} - -func findSigningCert(mspConfigPath string) (string, error) { - p := filepath.Join(mspConfigPath, "signcerts") - files, err := os.ReadDir(p) - if err != nil { - return "", errors.Wrapf(err, "error while searching pem in %s", mspConfigPath) - } - - // return first pem we find - for _, f := range files { - if !f.IsDir() && strings.HasSuffix(f.Name(), ".pem") { - return filepath.Join(p, f.Name()), nil - } - } - - return "", errors.Errorf("cannot find pem in %s", mspConfigPath) -} - -func populateWallet(wallet *gateway.Wallet, config *Config) error { - logger.Debugf("============ Populating wallet ============") - certPath, err := findSigningCert(config.CorePeerMSPConfigPath) - if err != nil { - return err - } - - // read the certificate pem - cert, err := os.ReadFile(filepath.Clean(certPath)) - if err != nil { - return err - } - - keyDir := filepath.Join(config.CorePeerMSPConfigPath, "keystore") - // there's a single file in this dir containing the private key - files, err := os.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 := os.ReadFile(filepath.Clean(keyPath)) - if err != nil { - return err - } - - identity := gateway.NewX509Identity(config.CorePeerLocalMSPID, string(cert), string(key)) - - return wallet.Put("appUser", identity) -} - -func newContract(config *Config) fpc.Contract { - - wallet := gateway.NewInMemoryWallet() - err := populateWallet(wallet, config) - if err != nil { - logger.Fatalf("Failed to populate wallet contents: %v", err) - } - - gw, err := gateway.Connect( - gateway.WithConfig(cfg.FromFile(filepath.Clean(config.GatewayConfigPath))), - gateway.WithIdentity(wallet, "appUser"), - ) - if err != nil { - logger.Fatalf("Failed to connect to gateway: %v", err) - } - defer gw.Close() - - network, err := gw.GetNetwork(config.ChannelId) - if err != nil { - logger.Fatalf("Failed to get network: %v", err) - } - - // Get FPC Contract - contract := fpc.GetContract(network, config.ChaincodeId) - return contract -} - -func (c *Client) Invoke(function string, args ...string) string { - logger.Infof("--> Invoke FPC chaincode with %s %s", function, args) - result, err := c.contract.SubmitTransaction(function, args...) - if err != nil { - logger.Infof("Failed to Submit transaction: %v", err) - } - logger.Debugf("--> Result: %s", string(result)) - return string(result) -} - -func (c *Client) Query(function string, args ...string) string { - logger.Debugf("--> Query FPC chaincode with %s %s", function, args) - result, err := c.contract.EvaluateTransaction(function, args...) - if err != nil { - logger.Fatalf("Failed to evaluate transaction: %v", err) - } - logger.Debugf("--> Result: %s", string(result)) - return string(result) -} diff --git a/samples/application/ccapi/fpcUtils/logging.go b/samples/application/ccapi/fpcUtils/logging.go deleted file mode 100644 index f5c5d2d34..000000000 --- a/samples/application/ccapi/fpcUtils/logging.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package fpcUtils - -import ( - "fmt" - - "github.com/hyperledger/fabric-sdk-go/pkg/common/logging" - "github.com/hyperledger/fabric-sdk-go/pkg/core/logging/api" - "github.com/hyperledger/fabric/common/flogging" -) - -var logger = flogging.MustGetLogger("fpc.cli") - -func init() { - logging.Initialize(&provider{}) -} - -type provider struct { -} - -func (p *provider) GetLogger(module string) api.Logger { - name := "client.sdk-go" - e := &extendedFlogger{flogging.MustGetLogger(name)} - - return e -} - -type extendedFlogger struct { - *flogging.FabricLogger -} - -func (e *extendedFlogger) Fatalln(v ...interface{}) { - e.Fatal(v...) -} - -func (e *extendedFlogger) Panicln(v ...interface{}) { - e.Panic(v...) -} - -func (e *extendedFlogger) Print(v ...interface{}) { - fmt.Print(v...) -} - -func (e *extendedFlogger) Printf(format string, v ...interface{}) { - fmt.Printf(format, v...) -} - -func (e *extendedFlogger) Println(v ...interface{}) { - fmt.Println(v...) - -} - -func (e *extendedFlogger) Debugln(args ...interface{}) { - e.Debug(args...) -} - -func (e *extendedFlogger) Infoln(args ...interface{}) { - e.Info(args...) -} - -func (e *extendedFlogger) Warnln(args ...interface{}) { - e.Warn(args...) -} - -func (e *extendedFlogger) Errorln(args ...interface{}) { - e.Error(args...) -} diff --git a/samples/application/ccapi/handlers/invoke.go b/samples/application/ccapi/handlers/invoke.go deleted file mode 100644 index 0a2e3dbb1..000000000 --- a/samples/application/ccapi/handlers/invoke.go +++ /dev/null @@ -1,100 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func Invoke(c *gin.Context) { - // Get channel information from request - req := make(map[string]interface{}) - err := c.BindJSON(&req) - if err != nil { - common.Abort(c, http.StatusBadRequest, err) - return - } - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - txName := c.Param("txname") - - var collections []string - collectionsQuery := c.Query("@collections") - if collectionsQuery != "" { - collectionsByte, err := base64.StdEncoding.DecodeString(collectionsQuery) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - - err = json.Unmarshal(collectionsByte, &collections) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - } else { - collectionsQuery := c.QueryArray("collections") - if len(collectionsQuery) > 0 { - collections = collectionsQuery - } else { - collections = []string{c.Query("collections")} - } - } - - transientMap := make(map[string]interface{}) - for key, value := range req { - if key[0] == '~' { - keyTrimmed := strings.TrimPrefix(key, "~") - transientMap[keyTrimmed] = value - delete(req, key) - } - } - - args, err := json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - transientMapByte, err := json.Marshal(transientMap) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "error": err.Error(), - }) - return - } - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.Invoke(channelName, chaincodeName, txName, user, argList, transientMapByte) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res.Payload, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/invokeFpc.go b/samples/application/ccapi/handlers/invokeFpc.go deleted file mode 100644 index d63a11850..000000000 --- a/samples/application/ccapi/handlers/invokeFpc.go +++ /dev/null @@ -1,93 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func InvokeFpc(c *gin.Context) { - // Get channel information from request - req := make(map[string]interface{}) - err := c.BindJSON(&req) - if err != nil { - common.Abort(c, http.StatusBadRequest, err) - return - } - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - txName := c.Param("txname") - - var collections []string - collectionsQuery := c.Query("@collections") - if collectionsQuery != "" { - collectionsByte, err := base64.StdEncoding.DecodeString(collectionsQuery) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - - err = json.Unmarshal(collectionsByte, &collections) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - } else { - collectionsQuery := c.QueryArray("collections") - if len(collectionsQuery) > 0 { - collections = collectionsQuery - } else { - collections = []string{c.Query("collections")} - } - } - - transientMap := make(map[string]interface{}) - for key, value := range req { - if key[0] == '~' { - keyTrimmed := strings.TrimPrefix(key, "~") - transientMap[keyTrimmed] = value - delete(req, key) - } - } - - args, err := json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.InvokeFpc(channelName, chaincodeName, txName, argList) - - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/invokeFpcDefault.go b/samples/application/ccapi/handlers/invokeFpcDefault.go deleted file mode 100644 index d0dd3b050..000000000 --- a/samples/application/ccapi/handlers/invokeFpcDefault.go +++ /dev/null @@ -1,91 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "strings" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func InvokeFpcDefault(c *gin.Context) { - // Get transaction information from request - req := make(map[string]interface{}) - err := c.BindJSON(&req) - if err != nil { - common.Abort(c, http.StatusBadRequest, err) - return - } - txName := c.Param("txname") - - var collections []string - collectionsQuery := c.Query("@collections") - if collectionsQuery != "" { - collectionsByte, err := base64.StdEncoding.DecodeString(collectionsQuery) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - - err = json.Unmarshal(collectionsByte, &collections) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - } else { - collectionsQuery := c.QueryArray("collections") - if len(collectionsQuery) > 0 { - collections = collectionsQuery - } else { - collections = []string{c.Query("collections")} - } - } - - transientMap := make(map[string]interface{}) - for key, value := range req { - if key[0] == '~' { - keyTrimmed := strings.TrimPrefix(key, "~") - transientMap[keyTrimmed] = value - delete(req, key) - } - } - - args, err := json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.InvokeFpcDefault(txName, argList) - - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/invokeGateway.go b/samples/application/ccapi/handlers/invokeGateway.go deleted file mode 100644 index 123ad4db8..000000000 --- a/samples/application/ccapi/handlers/invokeGateway.go +++ /dev/null @@ -1,106 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "os" - "strings" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" - "github.com/pkg/errors" -) - -func InvokeGatewayDefault(c *gin.Context) { - channelName := os.Getenv("CHANNEL") - chaincodeName := os.Getenv("CCNAME") - - invokeGateway(c, channelName, chaincodeName) -} - -func InvokeGatewayCustom(c *gin.Context) { - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - - invokeGateway(c, channelName, chaincodeName) -} - -func invokeGateway(c *gin.Context, channelName, chaincodeName string) { - // Get request body - req := make(map[string]interface{}) - err := c.BindJSON(&req) - if err != nil { - common.Abort(c, http.StatusBadRequest, err) - return - } - - txName := c.Param("txname") - - // Get endorsers names - var endorsers []string - endorsersQuery := c.Query("@endorsers") - if endorsersQuery != "" { - endorsersByte, err := base64.StdEncoding.DecodeString(endorsersQuery) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @endorsers query parameter must be a base64-encoded JSON array of strings", - }) - return - } - - err = json.Unmarshal(endorsersByte, &endorsers) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @endorsers query parameter must be a base64-encoded JSON array of strings", - }) - return - } - } - - // Make transient request - transientMap := make(map[string]interface{}) - for key, value := range req { - if key[0] == '~' { - keyTrimmed := strings.TrimPrefix(key, "~") - transientMap[keyTrimmed] = value - delete(req, key) - } - } - - transientBytes, _ := json.Marshal(transientMap) - if len(transientMap) == 0 { - transientMap = nil - } - - // Make args - reqBytes, err := json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, errors.Wrap(err, "failed to marshal req body")) - return - } - - // Invoke - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - result, err := chaincode.InvokeGateway(channelName, chaincodeName, txName, user, []string{string(reqBytes)}, transientBytes, endorsers) - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - // Parse response - var payload interface{} - err = json.Unmarshal(result, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, http.StatusOK, nil) -} diff --git a/samples/application/ccapi/handlers/invokeV1.go b/samples/application/ccapi/handlers/invokeV1.go deleted file mode 100644 index f6eca2985..000000000 --- a/samples/application/ccapi/handlers/invokeV1.go +++ /dev/null @@ -1,102 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "os" - "strings" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func InvokeV1(c *gin.Context) { - // Get channel information from request - req := make(map[string]interface{}) - err := c.BindJSON(&req) - if err != nil { - common.Abort(c, http.StatusBadRequest, err) - return - } - - channelName := os.Getenv("CHANNEL") - chaincodeName := os.Getenv("CCNAME") - txName := c.Param("txname") - - var collections []string - collectionsQuery := c.Query("@collections") - if collectionsQuery != "" { - collectionsByte, err := base64.StdEncoding.DecodeString(collectionsQuery) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - - err = json.Unmarshal(collectionsByte, &collections) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{ - "error": "the @collections query parameter must be a base64-encoded JSON array of strings", - }) - return - } - } else { - collectionsQuery := c.QueryArray("collections") - if len(collectionsQuery) > 0 { - collections = collectionsQuery - } else { - collections = []string{c.Query("collections")} - } - } - - transientMap := make(map[string]interface{}) - for key, value := range req { - if key[0] == '~' { - keyTrimmed := strings.TrimPrefix(key, "~") - transientMap[keyTrimmed] = value - delete(req, key) - } - } - - args, err := json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - transientMapByte, err := json.Marshal(transientMap) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "error": err.Error(), - }) - return - } - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.Invoke(channelName, chaincodeName, txName, user, argList, transientMapByte) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res.Payload, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/qscc.go b/samples/application/ccapi/handlers/qscc.go deleted file mode 100644 index d999d3934..000000000 --- a/samples/application/ccapi/handlers/qscc.go +++ /dev/null @@ -1,451 +0,0 @@ -package handlers - -import ( - "encoding/hex" - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" - protos "github.com/hyperledger/fabric-protos-go-apiv2/common" - queryresultprotos "github.com/hyperledger/fabric-protos-go-apiv2/ledger/queryresult" - rwsetprotos "github.com/hyperledger/fabric-protos-go-apiv2/ledger/rwset" - mspprotos "github.com/hyperledger/fabric-protos-go-apiv2/msp" - peerprotos "github.com/hyperledger/fabric-protos-go-apiv2/peer" - "github.com/pkg/errors" - "google.golang.org/protobuf/proto" -) - -func QueryQSCC(c *gin.Context) { - channelName := c.Param("channelName") - txname := c.Param("txname") - - switch txname { - case "getBlockByNumber": - getBlockByNumber(c, channelName) - case "getBlockByHash": - getBlockByHash(c, channelName) - case "getTransactionByID": - getTransactionByID(c, channelName) - case "getChainInfo": - getChainInfo(c, channelName) - case "getBlockByTxID": - getBlockByTxID(c, channelName) - default: - common.Abort(c, http.StatusNotFound, fmt.Errorf("unknown endpoint call")) - } -} - -func getChainInfo(c *gin.Context, channelName string) { - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - result, err := chaincode.QueryGateway(channelName, "qscc", "GetChainInfo", user, []string{channelName}) - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - var chainInfo protos.BlockchainInfo - - err = proto.Unmarshal(result, &chainInfo) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - chainInfoRes := map[string]interface{}{ - "height": chainInfo.Height, - "current_block_hash": hex.EncodeToString(chainInfo.CurrentBlockHash), - "previous_block_hash": hex.EncodeToString(chainInfo.PreviousBlockHash), - } - - common.Respond(c, chainInfoRes, http.StatusOK, nil) -} - -func getBlockByNumber(c *gin.Context, channelName string) { - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - number, ok := c.GetQuery("number") - if !ok { - common.Abort(c, http.StatusBadRequest, fmt.Errorf("missing number")) - return - } - - result, err := chaincode.QueryGateway(channelName, "qscc", "GetBlockByNumber", user, []string{channelName, number}) - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - blockMap, err := decodeBlock(result) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, blockMap, http.StatusOK, nil) -} - -func getBlockByTxID(c *gin.Context, channelName string) { - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - txid, ok := c.GetQuery("txid") - if !ok { - common.Abort(c, http.StatusBadRequest, fmt.Errorf("missing number")) - return - } - - result, err := chaincode.QueryGateway(channelName, "qscc", "GetBlockByTxID", user, []string{channelName, txid}) - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - blockMap, err := decodeBlock(result) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, blockMap, http.StatusOK, nil) -} - -func getBlockByHash(c *gin.Context, channelName string) { - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - hash, ok := c.GetQuery("hash") - if !ok { - common.Abort(c, http.StatusBadRequest, fmt.Errorf("missing hash")) - return - } - - hashBytes, err := hex.DecodeString(hash) - - if err != nil { - common.Abort(c, http.StatusBadRequest, fmt.Errorf("invalid hash format: %s", hash)) - return - } - - result, err := chaincode.QueryGateway(channelName, "qscc", "GetBlockByHash", user, []string{channelName, string(hashBytes)}) - - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - blockMap, err := decodeBlock(result) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, blockMap, http.StatusOK, nil) -} - -func getTransactionByID(c *gin.Context, channelName string) { - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - fmt.Println("getting txid") - txid, ok := c.GetQuery("txid") - if !ok { - common.Abort(c, http.StatusBadRequest, fmt.Errorf("missing txid")) - return - } - - fmt.Println("calling GetTransactionByID") - result, err := chaincode.QueryGateway(channelName, "qscc", "GetTransactionByID", user, []string{channelName, txid}) - if err != nil { - fmt.Println("error calling GetTransactionByID: ", err) - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - fmt.Println("decoding transaction") - m, err := decodeProcessedTransaction(result) - if err != nil { - fmt.Println("error decoding transaction: ", err) - common.Abort(c, http.StatusInternalServerError, err) - return - } - - fmt.Println("responding") - common.Respond(c, m, http.StatusOK, nil) -} - -func decodeBlock(b []byte) (map[string]interface{}, error) { - var block protos.Block - - err := proto.Unmarshal(b, &block) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal block") - } - - blockDataProto := block.GetData() - dataProto := blockDataProto.GetData() - - dataList := make([]interface{}, 0) - - for _, dataP := range dataProto { - var envelope protos.Envelope - - err := proto.Unmarshal(dataP, &envelope) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal envelope") - } - - var payload protos.Payload - - err = proto.Unmarshal(envelope.Payload, &payload) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal payload") - } - - var channelHeader protos.ChannelHeader - - err = proto.Unmarshal(payload.Header.ChannelHeader, &channelHeader) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal channel header") - } - - var tx interface{} - if channelHeader.Type == int32(protos.HeaderType_ENDORSER_TRANSACTION) { - tx, err = decodeTransaction(payload.Data) - if err != nil { - return nil, errors.Wrap(err, "failed to decode transaction") - } - } else { - tx = payload.Data - } - - dataList = append(dataList, map[string]interface{}{ - "payload": map[string]interface{}{ - "header": map[string]interface{}{ - "channel_header": &channelHeader, - "signature_header": payload.Header.SignatureHeader, - }, - "data": tx, - }, - "signature": envelope.Signature, - }) - - } - - blockMap := map[string]interface{}{ - "header": map[string]interface{}{ - "number": block.Header.Number, - "previous_hash": hex.EncodeToString(block.Header.PreviousHash), - "data_hash": hex.EncodeToString(block.Header.DataHash), - }, - "metadata": block.Metadata, - "data": dataList, - } - return blockMap, nil -} - -func decodeTransaction(b []byte) (map[string]interface{}, error) { - var transaction peerprotos.Transaction - - err := proto.Unmarshal(b, &transaction) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal transaction") - } - - actions := transaction.GetActions() - - actionList := make([]interface{}, 0) - for _, action := range actions { - headerB := action.GetHeader() - payloadB := action.GetPayload() - - var sigHeader protos.SignatureHeader - err = proto.Unmarshal(headerB, &sigHeader) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal signature header") - } - - var creator mspprotos.SerializedIdentity - err = proto.Unmarshal(sigHeader.Creator, &creator) - if err != nil { - return nil, errors.Wrap(err, fmt.Sprintf("failed to unmarshal creator, %s", string(sigHeader.Creator))) - } - - var ccActionPayload peerprotos.ChaincodeActionPayload - err = proto.Unmarshal(payloadB, &ccActionPayload) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal chaincode action payload") - } - - var ccProposalPayload peerprotos.ChaincodeProposalPayload - err = proto.Unmarshal(ccActionPayload.ChaincodeProposalPayload, &ccProposalPayload) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal chaincode proposal payload") - } - - var input peerprotos.ChaincodeInvocationSpec - err = proto.Unmarshal(ccProposalPayload.Input, &input) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal chaincode invocation spec") - } - - args := input.ChaincodeSpec.Input.Args - - inputList := make([]string, 0) - for _, arg := range args { - inputList = append(inputList, string(arg)) - } - - ccEndorsedAction := ccActionPayload.Action - - var proposalResponsePayload peerprotos.ProposalResponsePayload - err = proto.Unmarshal(ccEndorsedAction.ProposalResponsePayload, &proposalResponsePayload) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal proposal response payload") - } - - extension := proposalResponsePayload.Extension - proposalHash := proposalResponsePayload.ProposalHash - - var chaincodeAction peerprotos.ChaincodeAction - err = proto.Unmarshal(extension, &chaincodeAction) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal chaincode action") - } - - var txRWSet rwsetprotos.TxReadWriteSet - err = proto.Unmarshal(chaincodeAction.Results, &txRWSet) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal tx read write set") - } - - nsRWList := make([]interface{}, 0) - for _, nsRWSet := range txRWSet.NsRwset { - var kvSet queryresultprotos.KV - err = proto.Unmarshal(nsRWSet.Rwset, &kvSet) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal kv read write set") - } - - nsRWList = append(nsRWList, map[string]interface{}{ - "namespace": nsRWSet.Namespace, - "rwset": map[string]interface{}{ - "key": kvSet.Key, - "value": string(kvSet.Value), - "namespace": kvSet.Namespace, - }, - "collections": nsRWSet.CollectionHashedRwset, - }) - } - - endorsements := ccEndorsedAction.Endorsements - - endorsementList := make([]interface{}, 0) - for _, endorsement := range endorsements { - var endorser mspprotos.SerializedIdentity - err = proto.Unmarshal(endorsement.Endorser, &endorser) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal endorser") - } - - endorsementList = append(endorsementList, map[string]interface{}{ - "endorser": &endorser, - "signature": endorsement.Signature, - }) - } - - actionList = append(actionList, map[string]interface{}{ - "header": map[string]interface{}{ - "creator": &creator, - "nonce": sigHeader.Nonce, - }, - "payload": map[string]interface{}{ - "chaincode_proposal_payload": map[string]interface{}{ - "chaincode_id": input.ChaincodeSpec.ChaincodeId, - // "type": input.ChaincodeSpec.Type, - // "timeout": input.ChaincodeSpec.Timeout, - "input": inputList, - }, - "action": map[string]interface{}{ - "proposal_response_payload": map[string]interface{}{ - "proposal_hash": proposalHash, - "extension": map[string]interface{}{ - "results": map[string]interface{}{ - "ns_rwset": nsRWList, - "data_model": txRWSet.DataModel, - }, - "response": map[string]interface{}{ - "status": chaincodeAction.Response.Status, - "message": chaincodeAction.Response.Message, - "payload": string(chaincodeAction.Response.Payload), - }, - "chaincode_id": chaincodeAction.ChaincodeId, - "events": chaincodeAction.Events, - }, - }, - "endorsements": endorsementList, - }, - }, - }) - } - - transactionMap := map[string]interface{}{ - "actions": actionList, - } - - return transactionMap, nil -} - -func decodeProcessedTransaction(t []byte) (map[string]interface{}, error) { - var processedTransaction peerprotos.ProcessedTransaction - err := proto.Unmarshal(t, &processedTransaction) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal transaction") - } - - transactionEnv := processedTransaction.TransactionEnvelope - transactionPayload := transactionEnv.GetPayload() - - var payload protos.Payload - - err = proto.Unmarshal(transactionPayload, &payload) - if err != nil { - return nil, errors.Wrap(err, "failed to unmarshal payload") - } - - transaction, err := decodeTransaction(payload.Data) - if err != nil { - return nil, errors.Wrap(err, "failed to decode transaction") - } - - processedTransactionMap := map[string]interface{}{ - "payload": transaction, - "signature": transactionEnv.Signature, - } - - return processedTransactionMap, nil -} \ No newline at end of file diff --git a/samples/application/ccapi/handlers/query.go b/samples/application/ccapi/handlers/query.go deleted file mode 100644 index 0e013d4e5..000000000 --- a/samples/application/ccapi/handlers/query.go +++ /dev/null @@ -1,60 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func Query(c *gin.Context) { - var args []byte - var err error - - if c.Request.Method == "GET" { - request := c.Query("@request") - if request != "" { - args, _ = base64.StdEncoding.DecodeString(request) - } - } else if c.Request.Method == "POST" { - req := make(map[string]interface{}) - c.ShouldBind(&req) - args, err = json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - } - - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - txName := c.Param("txname") - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.Query(channelName, chaincodeName, txName, user, argList) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res.Payload, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/queryFpc.go b/samples/application/ccapi/handlers/queryFpc.go deleted file mode 100644 index 8a059618f..000000000 --- a/samples/application/ccapi/handlers/queryFpc.go +++ /dev/null @@ -1,60 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func QueryFpc(c *gin.Context) { - var args []byte - var err error - - if c.Request.Method == "GET" { - request := c.Query("@request") - if request != "" { - args, _ = base64.StdEncoding.DecodeString(request) - } - } else if c.Request.Method == "POST" { - req := make(map[string]interface{}) - c.ShouldBind(&req) - args, err = json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - } - - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - txName := c.Param("txname") - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.QueryFpc(chaincodeName, channelName, txName, argList) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/queryFpcDefault.go b/samples/application/ccapi/handlers/queryFpcDefault.go deleted file mode 100644 index 38a740389..000000000 --- a/samples/application/ccapi/handlers/queryFpcDefault.go +++ /dev/null @@ -1,58 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func QueryFpcDefault(c *gin.Context) { - var args []byte - var err error - - if c.Request.Method == "GET" { - request := c.Query("@request") - if request != "" { - args, _ = base64.StdEncoding.DecodeString(request) - } - } else if c.Request.Method == "POST" { - req := make(map[string]interface{}) - c.ShouldBind(&req) - args, err = json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - } - - txName := c.Param("txname") - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.QueryFpcDefault(txName, argList) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/handlers/queryGateway.go b/samples/application/ccapi/handlers/queryGateway.go deleted file mode 100644 index 2cee7c3f9..000000000 --- a/samples/application/ccapi/handlers/queryGateway.go +++ /dev/null @@ -1,72 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "os" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func QueryGatewayDefault(c *gin.Context) { - channelName := os.Getenv("CHANNEL") - chaincodeName := os.Getenv("CCNAME") - - queryGateway(c, channelName, chaincodeName) -} - -func QueryGatewayCustom(c *gin.Context) { - channelName := c.Param("channelName") - chaincodeName := c.Param("chaincodeName") - - queryGateway(c, channelName, chaincodeName) -} - -func queryGateway(c *gin.Context, channelName, chaincodeName string) { - var args []byte - var err error - - // Get request data - if c.Request.Method == "GET" { - request := c.Query("@request") - if request != "" { - args, _ = base64.StdEncoding.DecodeString(request) - } - } else if c.Request.Method == "POST" { - req := make(map[string]interface{}) - c.ShouldBind(&req) - args, err = json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - } - - txName := c.Param("txname") - - // Query - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - result, err := chaincode.QueryGateway(channelName, chaincodeName, txName, user, []string{string(args)}) - if err != nil { - err, status := common.ParseError(err) - common.Abort(c, status, err) - return - } - - // Parse response - var payload interface{} - err = json.Unmarshal(result, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, http.StatusOK, nil) -} diff --git a/samples/application/ccapi/handlers/queryV1.go b/samples/application/ccapi/handlers/queryV1.go deleted file mode 100644 index a68d30e82..000000000 --- a/samples/application/ccapi/handlers/queryV1.go +++ /dev/null @@ -1,61 +0,0 @@ -package handlers - -import ( - "encoding/base64" - "encoding/json" - "net/http" - "os" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/common" -) - -func QueryV1(c *gin.Context) { - var args []byte - var err error - - if c.Request.Method == "GET" { - request := c.Query("@request") - if request != "" { - args, _ = base64.StdEncoding.DecodeString(request) - } - } else if c.Request.Method == "POST" { - req := make(map[string]interface{}) - c.ShouldBind(&req) - args, err = json.Marshal(req) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - } - - channelName := os.Getenv("CHANNEL") - chaincodeName := os.Getenv("CCNAME") - txName := c.Param("txname") - - argList := [][]byte{} - if args != nil { - argList = append(argList, args) - } - - user := c.GetHeader("User") - if user == "" { - user = "Admin" - } - - res, status, err := chaincode.Query(channelName, chaincodeName, txName, user, argList) - if err != nil { - common.Abort(c, status, err) - return - } - - var payload interface{} - err = json.Unmarshal(res.Payload, &payload) - if err != nil { - common.Abort(c, http.StatusInternalServerError, err) - return - } - - common.Respond(c, payload, status, err) -} diff --git a/samples/application/ccapi/main.go b/samples/application/ccapi/main.go deleted file mode 100644 index ac39d69ad..000000000 --- a/samples/application/ccapi/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "context" - "log" - "os" - "os/signal" - - "github.com/gin-contrib/cors" - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/chaincode" - "github.com/hyperledger-labs/ccapi/server" - "github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab" -) - -func main() { - ctx, cancel := context.WithCancel(context.Background()) - - // Create gin handler and start server - r := gin.Default() - r.Use(cors.New(cors.Config{ - AllowOrigins: []string{ - "http://localhost:8080", // Test addresses - "*", - }, - AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, - AllowHeaders: []string{"Authorization", "Origin", "Content-Type"}, - AllowCredentials: true, - })) - go server.Serve(r, ctx) - // Events are not integrated with FPC - if os.Getenv("FPC_ENABLED") != "true" { - - // Register to chaincode events - go chaincode.WaitForEvent(os.Getenv("CHANNEL"), os.Getenv("CCNAME"), "eventName", func(ccEvent *fab.CCEvent) { - log.Println("Received CC event: ", ccEvent) - }) - - chaincode.RegisterForEvents() - } - - quit := make(chan os.Signal, 1) - signal.Notify(quit, os.Interrupt) - - <-quit - cancel() -} diff --git a/samples/application/ccapi/routes/chaincode.go b/samples/application/ccapi/routes/chaincode.go deleted file mode 100644 index 543e9c99d..000000000 --- a/samples/application/ccapi/routes/chaincode.go +++ /dev/null @@ -1,68 +0,0 @@ -package routes - -import ( - "os" - - "github.com/hyperledger-labs/ccapi/handlers" - - "github.com/gin-gonic/gin" -) - -func addCCRoutes(rg *gin.RouterGroup) { - if os.Getenv("FPC_ENABLED") == "true" { - //Use FPC Handlers - rg.POST("/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeFpc) - rg.PUT("/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeFpc) - rg.DELETE("/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeFpc) - rg.POST("/:channelName/:chaincodeName/query/:txname", handlers.QueryFpc) - rg.GET("/:channelName/:chaincodeName/query/:txname", handlers.QueryFpc) - - rg.POST("/invoke/:txname/", handlers.InvokeFpcDefault) - rg.POST("/invoke/:txname", handlers.InvokeFpcDefault) - rg.PUT("/invoke/:txname/", handlers.InvokeFpcDefault) - rg.PUT("/invoke/:txname", handlers.InvokeFpcDefault) - rg.DELETE("/invoke/:txname/", handlers.InvokeFpcDefault) - rg.DELETE("/invoke/:txname", handlers.InvokeFpcDefault) - rg.POST("/query/:txname/", handlers.QueryFpcDefault) - rg.POST("/query/:txname", handlers.QueryFpcDefault) - rg.GET("/query/:txname/", handlers.QueryFpcDefault) - rg.GET("/query/:txname", handlers.QueryFpcDefault) - - rg.GET("/:channelName/qscc/:txname", handlers.QueryQSCC) - - } else { - //Use Fabric Handlers - // Gateway routes - rg.POST("/gateway/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeGatewayCustom) - rg.PUT("/gateway/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeGatewayCustom) - rg.DELETE("/gateway/:channelName/:chaincodeName/invoke/:txname", handlers.InvokeGatewayCustom) - rg.POST("/gateway/:channelName/:chaincodeName/query/:txname", handlers.QueryGatewayCustom) - rg.GET("/gateway/:channelName/:chaincodeName/query/:txname", handlers.QueryGatewayCustom) - - rg.POST("/gateway/invoke/:txname", handlers.InvokeGatewayDefault) - rg.PUT("/gateway/invoke/:txname", handlers.InvokeGatewayDefault) - rg.DELETE("/gateway/invoke/:txname", handlers.InvokeGatewayDefault) - rg.POST("/gateway/query/:txname", handlers.QueryGatewayDefault) - rg.GET("/gateway/query/:txname", handlers.QueryGatewayDefault) - - // Other - rg.POST("/:channelName/:chaincodeName/invoke/:txname", handlers.Invoke) - rg.PUT("/:channelName/:chaincodeName/invoke/:txname", handlers.Invoke) - rg.DELETE("/:channelName/:chaincodeName/invoke/:txname", handlers.Invoke) - rg.POST("/:channelName/:chaincodeName/query/:txname", handlers.Query) - rg.GET("/:channelName/:chaincodeName/query/:txname", handlers.Query) - - rg.POST("/invoke/:txname/", handlers.InvokeV1) - rg.POST("/invoke/:txname", handlers.InvokeV1) - rg.PUT("/invoke/:txname/", handlers.InvokeV1) - rg.PUT("/invoke/:txname", handlers.InvokeV1) - rg.DELETE("/invoke/:txname/", handlers.InvokeV1) - rg.DELETE("/invoke/:txname", handlers.InvokeV1) - rg.POST("/query/:txname/", handlers.QueryV1) - rg.POST("/query/:txname", handlers.QueryV1) - rg.GET("/query/:txname/", handlers.QueryV1) - rg.GET("/query/:txname", handlers.QueryV1) - - rg.GET("/:channelName/qscc/:txname", handlers.QueryQSCC) - } -} diff --git a/samples/application/ccapi/routes/routes.go b/samples/application/ccapi/routes/routes.go deleted file mode 100644 index 6a1712332..000000000 --- a/samples/application/ccapi/routes/routes.go +++ /dev/null @@ -1,36 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/docs" - swaggerfiles "github.com/swaggo/files" - ginSwagger "github.com/swaggo/gin-swagger" -) - -// Register routes and handlers used by engine -func AddRoutesToEngine(r *gin.Engine) { - r.GET("/", func(c *gin.Context) { - c.Redirect(301, "/api-docs/index.html") - }) - - r.GET("/ping", func(c *gin.Context) { - c.JSON(200, gin.H{ - "status": "ok", - }) - }) - - // serve swagger files - docs.SwaggerInfo.BasePath = "/api" - r.StaticFile("/swagger.yaml", "./docs/swagger.yaml") - - url := ginSwagger.URL("/swagger.yaml") - r.GET("/api-docs/*any", ginSwagger.WrapHandler(swaggerfiles.Handler, url)) - - // CHANNEL routes - chaincodeRG := r.Group("/api") - addCCRoutes(chaincodeRG) - - // Update SDK route - sdkRG := r.Group("/sdk") - addSDKRoutes(sdkRG) -} diff --git a/samples/application/ccapi/routes/sdk.go b/samples/application/ccapi/routes/sdk.go deleted file mode 100644 index 417f6b06b..000000000 --- a/samples/application/ccapi/routes/sdk.go +++ /dev/null @@ -1,10 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" -) - -func addSDKRoutes(rg *gin.RouterGroup) { - // Update SDK route - // rg.POST("/update", handlers.UpdateSDK) -} diff --git a/samples/application/ccapi/server/server.go b/samples/application/ccapi/server/server.go deleted file mode 100644 index 4dbc5c06e..000000000 --- a/samples/application/ccapi/server/server.go +++ /dev/null @@ -1,92 +0,0 @@ -package server - -import ( - "context" - "log" - "net/http" - "os" - "sync" - "time" - - "github.com/gin-gonic/gin" - "github.com/hyperledger-labs/ccapi/common" - "github.com/hyperledger-labs/ccapi/routes" -) - -func defaultServer(r *gin.Engine) *http.Server { - return &http.Server{ - Addr: ":80", - Handler: r, - } -} - -// Serve starts the server with gin's default engine. -// Server gracefully shut's down -func Serve(r *gin.Engine, ctx context.Context) { - // Defer close sdk to clear cache and free memory - defer common.CloseSDK() - - if os.Getenv("FPC_ENABLED") == "true" { - common.InitFpcConfig() - } - - // Register routes and handlers - routes.AddRoutesToEngine(r) - - // Returns a http.Server from provided handler - srv := defaultServer(r) - - // listen and serve on 0.0.0.0:80 (for windows "localhost:80") - go func(server *http.Server) { - log.Println("Listening on port 80") - err := srv.ListenAndServe() - if err != http.ErrServerClosed { - log.Panic(err) - } - }(srv) - - // Graceful shutdown - <-ctx.Done() - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - if err := srv.Shutdown(ctx); err != nil { - log.Panic(err) - } - log.Println("Shutting down") -} - -// Serve sync starts the server with a given wait group. -// When server starts, the wait group counter is increased and processes -// that depend on server can be ran synchronously with it -func ServeSync(ctx context.Context, wg *sync.WaitGroup) { - gin.SetMode(gin.TestMode) - r := gin.New() - - routes.AddRoutesToEngine(r) - - srv := defaultServer(r) - - go func(server *http.Server) { - log.Println("Listening on port 80") - err := srv.ListenAndServe() - if err != http.ErrServerClosed { - log.Panic(err) - } - // finish wait group - time.Sleep(1 * time.Second) - wg.Done() - }(srv) - - wg.Add(1) - <-ctx.Done() - - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - if err := srv.Shutdown(ctx); err != nil { - log.Panic(err) - } - log.Println("Shutting down") -} diff --git a/samples/application/ccapi/web-client/docker-compose-goinitus.yaml b/samples/application/ccapi/web-client/docker-compose-goinitus.yaml deleted file mode 100644 index 2cb1acb3c..000000000 --- a/samples/application/ccapi/web-client/docker-compose-goinitus.yaml +++ /dev/null @@ -1,14 +0,0 @@ -version: '3' - -networks: - fabric_test: - external: true - -services: - goinitus: - image: goledger/cc-webclient:latest - container_name: goinitus - ports: - - "8080:80" - networks: - - fabric_test