fabric-samples/high-throughput/application-go/app.go
Mark S. Lewis 6130e1b9e8
Fix high-throughput sample (#1351)
Build failures because the startFabric.sh script specified that the
chaincode required initialization, which is both legacy behavior and is
unnecessary.

The chaincode is updated to use the Contract API instead of the legacy /
low-level chaincode API. The client application is also simplified.

Signed-off-by: Mark S. Lewis <Mark.S.Lewis@outlook.com>
2025-10-06 21:36:09 +09:00

175 lines
4.6 KiB
Go

/*
Copyright 2020 IBM All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package main
import (
"log"
"os"
"sync"
"sync/atomic"
"time"
"github.com/hyperledger/fabric-gateway/pkg/client"
"github.com/hyperledger/fabric-gateway/pkg/hash"
gatewaypb "github.com/hyperledger/fabric-protos-go-apiv2/gateway"
"google.golang.org/grpc/status"
)
func main() {
var function, variableName, change, sign string
if len(os.Args) <= 2 {
log.Println("Usage: function variableName")
log.Fatalf("functions: update delete prune get manyUpdates updatestandard delstandard getstandard manyUpdatesTraditional")
} else if (os.Args[1] == "update" || os.Args[1] == "manyUpdates" || os.Args[1] == "manyUpdatesTraditional") && len(os.Args) < 5 {
log.Fatalf("error: provide value and operation")
} else if len(os.Args) == 3 {
function = os.Args[1]
variableName = os.Args[2]
} else if len(os.Args) == 5 {
function = os.Args[1]
variableName = os.Args[2]
change = os.Args[3]
sign = os.Args[4]
}
clientConnection := newGrpcConnection()
defer clientConnection.Close()
gateway, err := client.Connect(
newIdentity(),
client.WithSign(newSign()),
client.WithHash(hash.SHA256),
client.WithClientConnection(clientConnection),
client.WithEvaluateTimeout(5*time.Second),
client.WithEndorseTimeout(15*time.Second),
client.WithSubmitTimeout(5*time.Second),
client.WithCommitStatusTimeout(1*time.Minute),
)
if err != nil {
panic(err)
}
defer gateway.Close()
contract := gateway.GetNetwork("mychannel").GetContract("bigdatacc")
// Handle different functions
switch function {
case "update":
update(contract, variableName, change, sign)
case "updatestandard":
updateStandard(contract, variableName, change, sign)
case "delete":
delete(contract, variableName)
case "prune":
prune(contract, variableName)
case "delstandard":
delStandard(contract, variableName)
case "get":
get(contract, variableName)
case "getstandard":
getStandard(contract, variableName)
case "manyUpdates":
manyUpdates(contract, "Update", variableName, change, sign)
get(contract, variableName)
case "manyUpdatesTraditional":
manyUpdates(contract, "UpdateStandard", variableName, change, sign)
getStandard(contract, variableName)
default:
log.Fatalln("Unkown function:", function)
}
}
func update(contract *client.Contract, variableName, change, sign string) {
result, err := contract.SubmitTransaction("Update", variableName, change, sign)
failOnError(err)
log.Println(string(result))
get(contract, variableName)
}
func updateStandard(contract *client.Contract, variableName, change, sign string) {
result, err := contract.SubmitTransaction("UpdateStandard", variableName, change, sign)
failOnError(err)
log.Printf("Value of variable %s: %s\n", variableName, result)
}
func delete(contract *client.Contract, variableName string) {
result, err := contract.SubmitTransaction("Delete", variableName)
failOnError(err)
log.Println(string(result))
}
func prune(contract *client.Contract, variableName string) {
result, err := contract.SubmitTransaction("Prune", variableName)
failOnError(err)
log.Println(string(result))
}
func delStandard(contract *client.Contract, variableName string) {
_, err := contract.SubmitTransaction("DelStandard", variableName)
failOnError(err)
log.Printf("Deleted %s.\n", variableName)
}
func get(contract *client.Contract, variableName string) {
result, err := contract.EvaluateTransaction("Get", variableName)
failOnError(err)
log.Printf("Value of variable %s: %s\n", variableName, result)
}
func getStandard(contract *client.Contract, variableName string) {
result, err := contract.EvaluateTransaction("GetStandard", variableName)
failOnError(err)
log.Printf("Value of variable %s: %s\n", variableName, result)
}
func manyUpdates(contract *client.Contract, function, variableName, change, sign string) {
log.Println("submitting 1000 concurrent updates...")
var failCount atomic.Uint32
var wg sync.WaitGroup
for range 1000 {
wg.Add(1)
go func() {
defer wg.Done()
_, err := contract.SubmitTransaction(function, variableName, change, sign)
if err != nil {
failCount.Add(1)
}
}()
}
wg.Wait()
n := failCount.Load()
if n > 0 {
log.Printf("%v submit failures.", n)
}
}
func failOnError(err error) {
if err == nil {
return
}
details := status.Convert(err).Details()
if len(details) > 0 {
log.Println("Error Details:")
for _, detail := range details {
switch detail := detail.(type) {
case *gatewaypb.ErrorDetail:
log.Printf("- address: %s\n mspId: %s\n message: %s\n", detail.Address, detail.MspId, detail.Message)
default:
log.Printf("- %s", detail)
}
}
}
log.Fatalf("error: %v", err)
}