From cf7aa047c4a52f2ff8ec13dd0425cea7e438acd6 Mon Sep 17 00:00:00 2001 From: nXtCyberNet Date: Wed, 10 Jun 2026 21:22:59 +0530 Subject: [PATCH] refactor the commands Signed-off-by: nXtCyberNet --- .github/workflows/test-fsat.yaml | 13 + .../trader-go/{ => commands}/commands.go | 4 +- .../applications/trader-go/commands/config.go | 17 + .../trader-go/{ => commands}/contract.go | 2 +- .../applications/trader-go/commands/create.go | 27 ++ .../applications/trader-go/commands/delete.go | 21 ++ .../trader-go/{ => commands}/expectedError.go | 8 +- .../trader-go/commands/getAllAssets.go | 31 ++ .../applications/trader-go/commands/listen.go | 81 +++++ .../applications/trader-go/commands/read.go | 33 ++ .../trader-go/commands/transact.go | 126 ++++++++ .../trader-go/commands/transfer.go | 21 ++ .../applications/trader-go/commands_impl.go | 296 ------------------ .../applications/trader-go/config.go | 14 - .../applications/trader-go/main.go | 10 +- full-stack-asset-transfer-guide/justfile | 6 +- .../tests/10-appdev-e2e-go.sh | 62 ++++ 17 files changed, 447 insertions(+), 325 deletions(-) rename full-stack-asset-transfer-guide/applications/trader-go/{ => commands}/commands.go (86%) create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/config.go rename full-stack-asset-transfer-guide/applications/trader-go/{ => commands}/contract.go (99%) create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/create.go create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/delete.go rename full-stack-asset-transfer-guide/applications/trader-go/{ => commands}/expectedError.go (70%) create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/getAllAssets.go create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/listen.go create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/read.go create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/transact.go create mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands/transfer.go delete mode 100644 full-stack-asset-transfer-guide/applications/trader-go/commands_impl.go create mode 100755 full-stack-asset-transfer-guide/tests/10-appdev-e2e-go.sh diff --git a/.github/workflows/test-fsat.yaml b/.github/workflows/test-fsat.yaml index 6b8ba951..ff34700b 100644 --- a/.github/workflows/test-fsat.yaml +++ b/.github/workflows/test-fsat.yaml @@ -31,6 +31,19 @@ jobs: - run: just test-appdev working-directory: full-stack-asset-transfer-guide + appdev-go: + runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }} + steps: + - uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v6 + with: + go-version-file: full-stack-asset-transfer-guide/applications/trader-go/go.mod + - name: Set up Full Stack Runtime + uses: ./.github/actions/fsat-setup + - run: just test-appdev-go + working-directory: full-stack-asset-transfer-guide + chaincode: runs-on: ${{ github.repository == 'hyperledger/fabric-samples' && 'fabric-ubuntu-22.04' || 'ubuntu-22.04' }} steps: diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/commands.go similarity index 86% rename from full-stack-asset-transfer-guide/applications/trader-go/commands.go rename to full-stack-asset-transfer-guide/applications/trader-go/commands/commands.go index 66157609..5a943b81 100644 --- a/full-stack-asset-transfer-guide/applications/trader-go/commands.go +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/commands.go @@ -1,10 +1,10 @@ -package main +package commands import "github.com/hyperledger/fabric-gateway/pkg/client" type Command func(gw *client.Gateway, args []string) error -var commands = map[string]Command{ +var Commands = map[string]Command{ "create": cmdCreate, "delete": cmdDelete, "getAllAssets": cmdGetAllAssets, diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/config.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/config.go new file mode 100644 index 00000000..226f75ab --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/config.go @@ -0,0 +1,17 @@ +package commands + +import "os" + +func channelName() string { + if v := os.Getenv("CHANNEL_NAME"); v != "" { + return v + } + return "mychannel" +} + +func chaincodeName() string { + if v := os.Getenv("CHAINCODE_NAME"); v != "" { + return v + } + return "asset-transfer" +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/contract.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/contract.go similarity index 99% rename from full-stack-asset-transfer-guide/applications/trader-go/contract.go rename to full-stack-asset-transfer-guide/applications/trader-go/commands/contract.go index 5858757a..65fcd7da 100644 --- a/full-stack-asset-transfer-guide/applications/trader-go/contract.go +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/contract.go @@ -1,4 +1,4 @@ -package main +package commands import ( "encoding/json" diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/create.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/create.go new file mode 100644 index 00000000..a3966cb7 --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/create.go @@ -0,0 +1,27 @@ +package commands + +import ( + "fmt" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +// cmdCreate creates a new asset on the ledger. +// Arguments: +func cmdCreate(gw *client.Gateway, args []string) error { + if len(args) < 3 { + return fmt.Errorf("arguments: ") + } + + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + return smartContract.CreateAsset(Asset{ + ID: args[0], + Owner: args[1], + Color: args[2], + Size: 1, + AppraisedValue: 1, + }) +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/delete.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/delete.go new file mode 100644 index 00000000..d9223a96 --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/delete.go @@ -0,0 +1,21 @@ +package commands + +import ( + "fmt" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +// cmdDelete deletes an asset from the ledger. +// Arguments: +func cmdDelete(gw *client.Gateway, args []string) error { + if len(args) < 1 { + return fmt.Errorf("arguments: ") + } + + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + return smartContract.DeleteAsset(args[0]) +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/expectedError.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/expectedError.go similarity index 70% rename from full-stack-asset-transfer-guide/applications/trader-go/expectedError.go rename to full-stack-asset-transfer-guide/applications/trader-go/commands/expectedError.go index 366e65c0..d1454d48 100644 --- a/full-stack-asset-transfer-guide/applications/trader-go/expectedError.go +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/expectedError.go @@ -1,10 +1,4 @@ -/* - * Copyright IBM Corp. All Rights Reserved. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package main +package commands // ExpectedError represents a known, expected application error that should be // displayed normally rather than treated as an unexpected failure. diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/getAllAssets.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/getAllAssets.go new file mode 100644 index 00000000..e19c0a2c --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/getAllAssets.go @@ -0,0 +1,31 @@ +package commands + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +// cmdGetAllAssets queries and prints all assets currently on the ledger. +func cmdGetAllAssets(gw *client.Gateway, _ []string) error { + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + assets, err := smartContract.GetAllAssets() + if err != nil { + return err + } + + data, err := json.MarshalIndent(assets, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal assets: %w", err) + } + + for _, line := range strings.Split(string(data), "\n") { + fmt.Println(line) + } + return nil +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/listen.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/listen.go new file mode 100644 index 00000000..01b68456 --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/listen.go @@ -0,0 +1,81 @@ +package commands + +import ( + "context" + "fmt" + "os" + "strconv" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +const startBlock = uint64(0) + +func cmdListen(gw *client.Gateway, _ []string) error { + network := gw.GetNetwork(channelName()) + + checkpointFile := os.Getenv("CHECKPOINT_FILE") + if checkpointFile == "" { + checkpointFile = "checkpoint.json" + } + + simulatedFailureCount, err := getSimulatedFailureCount() + if err != nil { + return err + } + + checkpointer, err := client.NewFileCheckpointer(checkpointFile) + if err != nil { + return fmt.Errorf("failed to create checkpointer: %w", err) + } + defer checkpointer.Close() + + displayBlock := checkpointer.BlockNumber() + if displayBlock == 0 { + displayBlock = startBlock + } + + fmt.Println("Starting event listening from block", displayBlock) + fmt.Println("Last processed transaction ID within block:", checkpointer.TransactionID()) + if simulatedFailureCount > 0 { + fmt.Println("Simulating a write failure every", simulatedFailureCount, "transactions") + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + events, err := network.ChaincodeEvents(ctx, chaincodeName(), + client.WithStartBlock(startBlock), + client.WithCheckpoint(checkpointer), + ) + if err != nil { + return fmt.Errorf("failed to start chaincode event subscription: %w", err) + } + + eventCount := 0 + for event := range events { + if simulatedFailureCount > 0 { + eventCount++ + if eventCount >= simulatedFailureCount { + eventCount = 0 + return &ExpectedError{Message: "Simulated write failure"} + } + } + fmt.Printf("Chaincode event: BlockNumber=%d TxID=%s Name=%s Payload=%s\n", + event.BlockNumber, event.TransactionID, event.EventName, string(event.Payload)) + } + + return nil +} + +func getSimulatedFailureCount() (int, error) { + value := os.Getenv("SIMULATED_FAILURE_COUNT") + if value == "" { + return 0, nil + } + count, err := strconv.Atoi(value) + if err != nil || count < 0 { + return 0, fmt.Errorf("invalid SIMULATED_FAILURE_COUNT value: %s", value) + } + return count, nil +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/read.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/read.go new file mode 100644 index 00000000..ba54e412 --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/read.go @@ -0,0 +1,33 @@ +package commands + +import ( + "encoding/json" + "fmt" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +// cmdRead reads and prints a single asset from the ledger. +// Arguments: +func cmdRead(gw *client.Gateway, args []string) error { + if len(args) < 1 { + return fmt.Errorf("arguments: ") + } + + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + asset, err := smartContract.ReadAsset(args[0]) + if err != nil { + return err + } + + data, err := json.MarshalIndent(asset, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal asset: %w", err) + } + + fmt.Println(string(data)) + return nil +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/transact.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/transact.go new file mode 100644 index 00000000..9b6b78df --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/transact.go @@ -0,0 +1,126 @@ +package commands + +import ( + "crypto/rand" + "encoding/hex" + "fmt" + "math/big" + "strings" + "sync" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +var ( + colors = []string{"red", "green", "blue"} + maxInitialSize = 10 + maxInitialVal = 1000 +) + +// cmdTransact runs a batch of concurrent create/update/delete transactions to demonstrate +func cmdTransact(gw *client.Gateway, _ []string) error { + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + app := &transactApp{smartContract: smartContract, batchSize: 6} + return app.run() +} + +type transactApp struct { + smartContract *AssetTransfer + batchSize int +} + +func (a *transactApp) run() error { + var wg sync.WaitGroup + errCh := make(chan error, a.batchSize) + + for i := 0; i < a.batchSize; i++ { + wg.Add(1) + go func() { + defer wg.Done() + if err := a.transact(); err != nil { + errCh <- err + } + }() + } + + wg.Wait() + close(errCh) + + var failures []string + for err := range errCh { + failures = append(failures, err.Error()) + } + if len(failures) > 0 { + return fmt.Errorf("%d failures:\n- %s", len(failures), strings.Join(failures, "\n- ")) + } + return nil +} + +func (a *transactApp) transact() error { + asset := a.newAsset() + + if err := a.smartContract.CreateAsset(asset); err != nil { + return err + } + fmt.Printf("Created asset %s\n", asset.ID) + + if randomInt(2) == 0 { + oldColor := asset.Color + asset.Color = differentElement(colors, oldColor) + if err := a.smartContract.UpdateAsset(asset); err != nil { + return err + } + fmt.Printf("Updated color of asset %s from %s to %s\n", asset.ID, oldColor, asset.Color) + } + + if randomInt(4) == 0 { + if err := a.smartContract.DeleteAsset(asset.ID); err != nil { + return err + } + fmt.Printf("Deleted asset %s\n", asset.ID) + } + + return nil +} + +func (a *transactApp) newAsset() Asset { + return Asset{ + ID: randomHexString(8), + Color: randomElement(colors), + Size: randomInt(maxInitialSize) + 1, + AppraisedValue: float64(randomInt(maxInitialVal) + 1), + } +} + +func randomHexString(length int) string { + b := make([]byte, (length+1)/2) + if _, err := rand.Read(b); err != nil { + panic(fmt.Sprintf("failed to generate random bytes: %v", err)) + } + return hex.EncodeToString(b)[:length] +} + +func randomInt(max int) int { + n, err := rand.Int(rand.Reader, big.NewInt(int64(max))) + if err != nil { + panic(fmt.Sprintf("failed to generate random int: %v", err)) + } + return int(n.Int64()) +} + +func randomElement(values []string) string { + return values[randomInt(len(values))] +} + +func differentElement(values []string, currentValue string) string { + var candidates []string + for _, v := range values { + if v != currentValue { + candidates = append(candidates, v) + } + } + return randomElement(candidates) +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands/transfer.go b/full-stack-asset-transfer-guide/applications/trader-go/commands/transfer.go new file mode 100644 index 00000000..94b82681 --- /dev/null +++ b/full-stack-asset-transfer-guide/applications/trader-go/commands/transfer.go @@ -0,0 +1,21 @@ +package commands + +import ( + "fmt" + + "github.com/hyperledger/fabric-gateway/pkg/client" +) + +// cmdTransfer transfers ownership of an asset to a new owner in a different organisation. +// Arguments: +func cmdTransfer(gw *client.Gateway, args []string) error { + if len(args) < 3 { + return fmt.Errorf("arguments: ") + } + + network := gw.GetNetwork(channelName()) + contract := network.GetContract(chaincodeName()) + + smartContract := NewAssetTransfer(contract) + return smartContract.TransferAsset(args[0], args[1], args[2]) +} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/commands_impl.go b/full-stack-asset-transfer-guide/applications/trader-go/commands_impl.go deleted file mode 100644 index aae27b28..00000000 --- a/full-stack-asset-transfer-guide/applications/trader-go/commands_impl.go +++ /dev/null @@ -1,296 +0,0 @@ -package main - -import ( - "context" - "crypto/rand" - "encoding/hex" - "encoding/json" - "fmt" - "math/big" - "os" - "strconv" - "strings" - "sync" - - "github.com/hyperledger/fabric-gateway/pkg/client" -) - -// cmdCreate creates a new asset on the ledger. -// Arguments: -func cmdCreate(gw *client.Gateway, args []string) error { - if len(args) < 3 { - return fmt.Errorf("arguments: ") - } - - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - return smartContract.CreateAsset(Asset{ - ID: args[0], - Owner: args[1], - Color: args[2], - Size: 1, - AppraisedValue: 1, - }) -} - -// cmdDelete deletes an asset from the ledger. -// Arguments: -func cmdDelete(gw *client.Gateway, args []string) error { - if len(args) < 1 { - return fmt.Errorf("arguments: ") - } - - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - return smartContract.DeleteAsset(args[0]) -} - -// cmdGetAllAssets queries and prints all assets currently on the ledger. -func cmdGetAllAssets(gw *client.Gateway, _ []string) error { - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - assets, err := smartContract.GetAllAssets() - if err != nil { - return err - } - - data, err := json.MarshalIndent(assets, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal assets: %w", err) - } - - for _, line := range strings.Split(string(data), "\n") { - fmt.Println(line) - } - return nil -} - -const startBlock = uint64(0) - -func cmdListen(gw *client.Gateway, _ []string) error { - network := gw.GetNetwork(channelName()) - - checkpointFile := os.Getenv("CHECKPOINT_FILE") - if checkpointFile == "" { - checkpointFile = "checkpoint.json" - } - - simulatedFailureCount, err := getSimulatedFailureCount() - if err != nil { - return err - } - - checkpointer, err := client.NewFileCheckpointer(checkpointFile) - if err != nil { - return fmt.Errorf("failed to create checkpointer: %w", err) - } - defer checkpointer.Close() - - displayBlock := checkpointer.BlockNumber() - if displayBlock == 0 { - displayBlock = startBlock - } - - fmt.Println("Starting event listening from block", displayBlock) - fmt.Println("Last processed transaction ID within block:", checkpointer.TransactionID()) - if simulatedFailureCount > 0 { - fmt.Println("Simulating a write failure every", simulatedFailureCount, "transactions") - } - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - events, err := network.ChaincodeEvents(ctx, chaincodeName(), - client.WithStartBlock(startBlock), - client.WithCheckpoint(checkpointer), - ) - if err != nil { - return fmt.Errorf("failed to start chaincode event subscription: %w", err) - } - - eventCount := 0 - for event := range events { - if simulatedFailureCount > 0 { - eventCount++ - if eventCount >= simulatedFailureCount { - eventCount = 0 - return &ExpectedError{Message: "Simulated write failure"} - } - } - fmt.Printf("Chaincode event: BlockNumber=%d TxID=%s Name=%s Payload=%s\n", - event.BlockNumber, event.TransactionID, event.EventName, string(event.Payload)) - } - - return nil -} - -func getSimulatedFailureCount() (int, error) { - value := os.Getenv("SIMULATED_FAILURE_COUNT") - if value == "" { - return 0, nil - } - count, err := strconv.Atoi(value) - if err != nil || count < 0 { - return 0, fmt.Errorf("invalid SIMULATED_FAILURE_COUNT value: %s", value) - } - return count, nil -} - -// cmdRead reads and prints a single asset from the ledger. -// Arguments: -func cmdRead(gw *client.Gateway, args []string) error { - if len(args) < 1 { - return fmt.Errorf("arguments: ") - } - - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - asset, err := smartContract.ReadAsset(args[0]) - if err != nil { - return err - } - - data, err := json.MarshalIndent(asset, "", " ") - if err != nil { - return fmt.Errorf("failed to marshal asset: %w", err) - } - - fmt.Println(string(data)) - return nil -} - -var ( - colors = []string{"red", "green", "blue"} - maxInitialSize = 10 - maxInitialVal = 1000 -) - -// cmdTransact runs a batch of concurrent create/update/delete transactions to demonstrate -func cmdTransact(gw *client.Gateway, _ []string) error { - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - app := &transactApp{smartContract: smartContract, batchSize: 6} - return app.run() -} - -type transactApp struct { - smartContract *AssetTransfer - batchSize int -} - -func (a *transactApp) run() error { - var wg sync.WaitGroup - errCh := make(chan error, a.batchSize) - - for i := 0; i < a.batchSize; i++ { - wg.Add(1) - go func() { - defer wg.Done() - if err := a.transact(); err != nil { - errCh <- err - } - }() - } - - wg.Wait() - close(errCh) - - var failures []string - for err := range errCh { - failures = append(failures, err.Error()) - } - if len(failures) > 0 { - return fmt.Errorf("%d failures:\n- %s", len(failures), strings.Join(failures, "\n- ")) - } - return nil -} - -func (a *transactApp) transact() error { - asset := a.newAsset() - - if err := a.smartContract.CreateAsset(asset); err != nil { - return err - } - fmt.Printf("Created asset %s\n", asset.ID) - - if randomInt(2) == 0 { - oldColor := asset.Color - asset.Color = differentElement(colors, oldColor) - if err := a.smartContract.UpdateAsset(asset); err != nil { - return err - } - fmt.Printf("Updated color of asset %s from %s to %s\n", asset.ID, oldColor, asset.Color) - } - - if randomInt(4) == 0 { - if err := a.smartContract.DeleteAsset(asset.ID); err != nil { - return err - } - fmt.Printf("Deleted asset %s\n", asset.ID) - } - - return nil -} - -func (a *transactApp) newAsset() Asset { - return Asset{ - ID: randomHexString(8), - Color: randomElement(colors), - Size: randomInt(maxInitialSize) + 1, - AppraisedValue: float64(randomInt(maxInitialVal) + 1), - } -} - -func randomHexString(length int) string { - b := make([]byte, (length+1)/2) - if _, err := rand.Read(b); err != nil { - panic(fmt.Sprintf("failed to generate random bytes: %v", err)) - } - return hex.EncodeToString(b)[:length] -} - -func randomInt(max int) int { - n, err := rand.Int(rand.Reader, big.NewInt(int64(max))) - if err != nil { - panic(fmt.Sprintf("failed to generate random int: %v", err)) - } - return int(n.Int64()) -} - -func randomElement(values []string) string { - return values[randomInt(len(values))] -} - -func differentElement(values []string, currentValue string) string { - var candidates []string - for _, v := range values { - if v != currentValue { - candidates = append(candidates, v) - } - } - return randomElement(candidates) -} - -// cmdTransfer transfers ownership of an asset to a new owner in a different organisation. -// Arguments: -func cmdTransfer(gw *client.Gateway, args []string) error { - if len(args) < 3 { - return fmt.Errorf("arguments: ") - } - - network := gw.GetNetwork(channelName()) - contract := network.GetContract(chaincodeName()) - - smartContract := NewAssetTransfer(contract) - return smartContract.TransferAsset(args[0], args[1], args[2]) -} diff --git a/full-stack-asset-transfer-guide/applications/trader-go/config.go b/full-stack-asset-transfer-guide/applications/trader-go/config.go index 1cee1d9a..207b77e5 100644 --- a/full-stack-asset-transfer-guide/applications/trader-go/config.go +++ b/full-stack-asset-transfer-guide/applications/trader-go/config.go @@ -25,20 +25,6 @@ func tlsCertPath() string { return os.Getenv("TLS_CERT") } -func channelName() string { - if v := os.Getenv("CHANNEL_NAME"); v != "" { - return v - } - return "mychannel" -} - -func chaincodeName() string { - if v := os.Getenv("CHAINCODE_NAME"); v != "" { - return v - } - return "asset-transfer" -} - func hostAlias() string { return os.Getenv("HOST_ALIAS") } diff --git a/full-stack-asset-transfer-guide/applications/trader-go/main.go b/full-stack-asset-transfer-guide/applications/trader-go/main.go index 2136c9ac..42bbbaf2 100644 --- a/full-stack-asset-transfer-guide/applications/trader-go/main.go +++ b/full-stack-asset-transfer-guide/applications/trader-go/main.go @@ -5,11 +5,13 @@ import ( "fmt" "os" "sort" + + "trader-go/commands" ) func main() { if err := run(); err != nil { - var expectedErr *ExpectedError + var expectedErr *commands.ExpectedError if errors.As(err, &expectedErr) { fmt.Println(err) } else { @@ -29,7 +31,7 @@ func run() error { commandName := args[0] commandArgs := args[1:] - command, ok := commands[commandName] + command, ok := commands.Commands[commandName] if !ok { printUsage() return fmt.Errorf("unknown command: %s", commandName) @@ -51,8 +53,8 @@ func run() error { } func printUsage() { - names := make([]string, 0, len(commands)) - for name := range commands { + names := make([]string, 0, len(commands.Commands)) + for name := range commands.Commands { names = append(names, name) } sort.Strings(names) diff --git a/full-stack-asset-transfer-guide/justfile b/full-stack-asset-transfer-guide/justfile index 664c0546..5f6fbf84 100644 --- a/full-stack-asset-transfer-guide/justfile +++ b/full-stack-asset-transfer-guide/justfile @@ -101,7 +101,7 @@ operator-crds: check-kube ############################################################################### # Run e2e tests of all scenarios -test: test-chaincode test-appdev test-cloud # test-ansible +test: test-chaincode test-appdev test-appdev-go test-cloud # test-ansible # Run an e2e test of the SmartContractDev scenario test-chaincode: @@ -111,6 +111,10 @@ test-chaincode: test-appdev: tests/10-appdev-e2e.sh +# Run an e2e test of the ApplicationDev Go scenario +test-appdev-go: + tests/10-appdev-e2e-go.sh + # Run an e2e test of the CloudNative scenario test-cloud: tests/20-cloud-e2e.sh diff --git a/full-stack-asset-transfer-guide/tests/10-appdev-e2e-go.sh b/full-stack-asset-transfer-guide/tests/10-appdev-e2e-go.sh new file mode 100755 index 00000000..5ea745ad --- /dev/null +++ b/full-stack-asset-transfer-guide/tests/10-appdev-e2e-go.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# +# Copyright contributors to the Hyperledgendary Full Stack Asset Transfer project +# +# SPDX-License-Identifier: Apache-2.0 +# + +set -v -eou pipefail + +# All tests run in the workshop root folder +cd "$(dirname "$0")"/.. + +export WORKSHOP_PATH="${PWD}" +export PATH="${WORKSHOP_PATH}/bin:${PATH}" +export FABRIC_CFG_PATH="${WORKSHOP_PATH}/config" + +"${WORKSHOP_PATH}/check.sh" + +CHAINCODE_PID= + +function exitHook() { + + # shut down the chaincode container/process + [ -n "${CHAINCODE_PID}" ] && kill "${CHAINCODE_PID}" + + # Shut down microfab + docker kill microfab &> /dev/null + + # Delete the network configuration and crypto material + rm -rf "${WORKSHOP_PATH}"/_cfg +} + +trap exitHook SIGINT SIGTERM EXIT + +just microfab + +source "${WORKSHOP_PATH}/_cfg/uf/org1admin.env" +just debugcc + +source "${WORKSHOP_PATH}/_cfg/uf/org1admin.env" +cd "${WORKSHOP_PATH}/contracts/asset-transfer-typescript" +npm install +npm run build +node_modules/.bin/fabric-chaincode-node server --chaincode-address="${CHAINCODE_SERVER_ADDRESS}" --chaincode-id="${CHAINCODE_ID}" & +CHAINCODE_PID=$! + +sleep 5 + +cd "${WORKSHOP_PATH}/applications/trader-go" +export ENDPOINT=org1peer-api.127-0-0-1.nip.io:8080 +export MSP_ID=org1MSP +export CERTIFICATE=../../_cfg/uf/_msp/org1/org1admin/msp/signcerts/cert.pem +export PRIVATE_KEY=../../_cfg/uf/_msp/org1/org1admin/msp/keystore/cert_sk +go build -o trader +./trader getAllAssets +./trader transact +./trader getAllAssets +./trader create banana bananaman yellow +./trader read banana +./trader delete banana +SIMULATED_FAILURE_COUNT=2 ./trader listen