From 9b199d4e0b4a7583f42b649b9928a32295080ac0 Mon Sep 17 00:00:00 2001 From: Stanislav Jakuschevskij Date: Fri, 18 Oct 2024 16:10:20 +0200 Subject: [PATCH] Add private data go application Created project directory, app.go and connect.go files. Reused the logic for connect.go from the events application and added second organization setup. Implemented private data transaction example in go as described in the main documentation in "Tutorials/Using Private Data in Fabric". Updated README.md with the command to run the go application and the script which runs the application in the Github Actions workflow. Fixed typos and punctuation in the private data typescript application. Signed-off-by: Stanislav Jakuschevskij --- asset-transfer-private-data/README.md | 10 +- .../application-gateway-go/app.go | 398 ++++++++++++++++++ .../application-gateway-go/connect.go | 111 +++++ .../application-gateway-go/go.mod | 23 + .../application-gateway-go/go.sum | 223 ++++++++++ .../application-gateway-typescript/src/app.ts | 26 +- ci/scripts/run-test-network-private.sh | 9 + 7 files changed, 784 insertions(+), 16 deletions(-) create mode 100644 asset-transfer-private-data/application-gateway-go/app.go create mode 100644 asset-transfer-private-data/application-gateway-go/connect.go create mode 100644 asset-transfer-private-data/application-gateway-go/go.mod create mode 100644 asset-transfer-private-data/application-gateway-go/go.sum diff --git a/asset-transfer-private-data/README.md b/asset-transfer-private-data/README.md index 8ee1528946..0df860a825 100644 --- a/asset-transfer-private-data/README.md +++ b/asset-transfer-private-data/README.md @@ -53,9 +53,9 @@ Like other samples, the Fabric test network is used to deploy and run this sampl # To deploy the go chaincode implementation ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-go -ccl go -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg '../asset-transfer-private-data/chaincode-go/collections_config.json' -ccep "OR('Org1MSP.peer','Org2MSP.peer')" - + # To deploy the typescript chaincode implementation - ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-typescript/ -ccl typescript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-typescript/collections_config.json + ./network.sh deployCC -ccn private -ccp ../asset-transfer-private-data/chaincode-typescript/ -ccl typescript -ccep "OR('Org1MSP.peer','Org2MSP.peer')" -cccg ../asset-transfer-private-data/chaincode-typescript/collections_config.json ``` 3. Run the application (from the `asset-transfer-private-data` folder). @@ -64,6 +64,10 @@ Like other samples, the Fabric test network is used to deploy and run this sampl cd application-gateway-typescript npm install npm start + + # To run the Go sample application + cd application-gateway-go + go run . ``` ## Clean up @@ -72,4 +76,4 @@ When you are finished, you can bring down the test network (from the `test-netwo ``` ./network.sh down -``` \ No newline at end of file +``` diff --git a/asset-transfer-private-data/application-gateway-go/app.go b/asset-transfer-private-data/application-gateway-go/app.go new file mode 100644 index 0000000000..5274e3ab56 --- /dev/null +++ b/asset-transfer-private-data/application-gateway-go/app.go @@ -0,0 +1,398 @@ +/* +Copyright 2024 IBM All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "strings" + "time" + + "github.com/hyperledger/fabric-gateway/pkg/client" + "github.com/hyperledger/fabric-gateway/pkg/hash" + "github.com/hyperledger/fabric-protos-go-apiv2/gateway" + "google.golang.org/grpc/status" +) + +type transient = map[string][]byte + +const ( + channelName = "mychannel" + chaincodeName = "private" + mspIDOrg1 = "Org1MSP" + mspIDOrg2 = "Org2MSP" + + // Collection names. + org1PrivateCollectionName = "Org1MSPPrivateCollection" + org2PrivateCollectionName = "Org2MSPPrivateCollection" + + Red = "\033[31m" + Reset = "\033[0m" +) + +// Use a unique key so that we can run multiple times. +var now = time.Now() +var assetID1 = fmt.Sprintf("asset%d", now.Unix()) +var assetID2 = fmt.Sprintf("asset%d", now.Unix()+1) + +func main() { + clientOrg1 := newGrpcConnection( + tlsCertPathOrg1, + peerEndpointOrg1, + peerNameOrg1, + ) + defer clientOrg1.Close() + + gatewayOrg1, err := client.Connect( + newIdentity(certDirectoryPathOrg1, mspIDOrg1), + client.WithSign(newSign(keyDirectoryPathOrg1)), + client.WithClientConnection(clientOrg1), + client.WithHash(hash.SHA256), + ) + if err != nil { + panic(err) + } + defer gatewayOrg1.Close() + + clientOrg2 := newGrpcConnection( + tlsCertPathOrg2, + peerEndpointOrg2, + peerNameOrg2, + ) + defer clientOrg2.Close() + + gatewayOrg2, err := client.Connect( + newIdentity(certDirectoryPathOrg2, mspIDOrg2), + client.WithSign(newSign(keyDirectoryPathOrg2)), + client.WithClientConnection(clientOrg2), + client.WithHash(hash.SHA256), + ) + if err != nil { + panic(err) + } + defer gatewayOrg2.Close() + + // Get the smart contract as an Org1 client. + contractOrg1 := gatewayOrg1.GetNetwork(channelName).GetContract(chaincodeName) + + // Get the smart contract as an Org1 client. + contractOrg2 := gatewayOrg2.GetNetwork(channelName).GetContract(chaincodeName) + + fmt.Println("~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") + + // Create new assets on the ledger. + createAssets(contractOrg1) + + // Read asset from the Org1's private data collection with ID in the given range. + getAssetByRange(contractOrg1) + + // Attempt to transfer asset without prior approval from Org2, transaction expected to fail. + fmt.Println("\nAttempt TransferAsset without prior AgreeToTransfer") + err = transferAsset(contractOrg1, assetID1) + if err == nil { + doFail("TransferAsset transaction succeeded when it was expected to fail") + } + fmt.Printf("*** Received expected error: %+v\n", errorWithDetails(err)) + + fmt.Println("\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~") + + // Read the asset by ID. + readAssetByID(contractOrg2, assetID1) + + // Make agreement to transfer the asset from Org1 to Org2. + agreeToTransfer(contractOrg2, assetID1) + + fmt.Println("\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") + + // Read transfer agreement. + readTransferAgreement(contractOrg1, assetID1) + + // Transfer asset to Org2. + if err := transferAsset(contractOrg1, assetID1); err != nil { + doFail(fmt.Sprintf("TransferAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) + } + + // Again ReadAsset: results will show that the buyer identity now owns the asset. + readAssetByID(contractOrg1, assetID1) + + // Confirm that transfer removed the private details from the Org1 collection. + org1ReadSuccess := readAssetPrivateDetails(contractOrg1, assetID1, org1PrivateCollectionName) + if org1ReadSuccess { + doFail(fmt.Sprintf("Asset private data still exists in %s", org1PrivateCollectionName)) + } + + fmt.Println("\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~") + + // Org2 can read asset private details: Org2 is owner, and private details exist in new owner's Collection. + org2ReadSuccess := readAssetPrivateDetails(contractOrg2, assetID1, org2PrivateCollectionName) + if !org2ReadSuccess { + doFail(fmt.Sprintf("Asset private data not found in %s", org2PrivateCollectionName)) + } + + fmt.Println("\nAttempt DeleteAsset using non-owner organization") + err = deleteAsset(contractOrg2, assetID2) + if err == nil { + doFail("DeleteAsset transaction succeeded when it was expected to fail") + } + fmt.Printf("*** Received expected error: %+v\n", errorWithDetails(err)) + + fmt.Println("\n~~~~~~~~~~~~~~~~ As Org1 Client ~~~~~~~~~~~~~~~~") + + // Delete AssetID2 as Org1. + if err := deleteAsset(contractOrg1, assetID2); err != nil { + doFail(fmt.Sprintf("DeleteAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) + } + + // Trigger a purge of the private data for the asset. + // The previous delete is optional if purge is used. + if err := purgeAsset(contractOrg1, assetID2); err != nil { + doFail(fmt.Sprintf("PurgeAsset transaction failed when it was expected to succeed: %+v\n", errorWithDetails(err))) + } +} + +func createAssets(contract *client.Contract) { + assetType := "ValuableAsset" + + fmt.Printf("\n--> Submit Transaction: CreateAsset, ID: %s\n", assetID1) + + type assetTransientInput struct { + ObjectType string + AssetID string + Color string + Size uint8 + AppraisedValue uint16 + } + + asset1Data := assetTransientInput{ + ObjectType: assetType, + AssetID: assetID1, + Color: "green", + Size: 20, + AppraisedValue: 100, + } + + if _, err := contract.Submit( + "CreateAsset", + client.WithTransient(transient{ + "asset_properties": marshal(asset1Data), + }), + ); err != nil { + panic(err) + } + + logTxCommitSuccess() + fmt.Printf("\n--> Submit Transaction: CreateAsset, ID: %s\n", assetID2) + + asset2Data := assetTransientInput{ + ObjectType: assetType, + AssetID: assetID2, + Color: "blue", + Size: 35, + AppraisedValue: 727, + } + + if _, err := contract.Submit( + "CreateAsset", + client.WithTransient(transient{ + "asset_properties": marshal(asset2Data), + }), + ); err != nil { + panic(err) + } + + logTxCommitSuccess() +} + +func getAssetByRange(contract *client.Contract) { + // GetAssetByRange returns assets on the ledger with ID in the range of startKey (inclusive) and endKey (exclusive). + fmt.Printf("\n--> Evaluate Transaction: GetAssetByRange from %s\n", org1PrivateCollectionName) + + resultBytes, err := contract.EvaluateTransaction("GetAssetByRange", assetID1, fmt.Sprintf("asset%d", now.Unix()+2)) + if err != nil { + panic(err) + } + + if len(resultBytes) == 0 { + doFail("Received empty query list for GetAssetByRange") + } + + fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) +} + +func readAssetByID(contract *client.Contract, assetID string) { + fmt.Printf("\n--> Evaluate Transaction: ReadAsset, ID: %s\n", assetID) + + resultBytes, err := contract.EvaluateTransaction("ReadAsset", assetID) + if err != nil { + panic(err) + } + + if len(resultBytes) == 0 { + doFail("Received empty result for ReadAsset") + } + + fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) +} + +func agreeToTransfer(contract *client.Contract, assetID string) { + // Buyer from Org2 agrees to buy the asset. + // To purchase the asset, the buyer needs to agree to the same value as the asset owner. + dataForAgreement := struct { + AssetID string `json:"assetID"` + AppraisedValue int `json:"appraisedValue"` + }{assetID, 100} + fmt.Printf("\n--> Submit Transaction: AgreeToTransfer, payload: %+v\n", dataForAgreement) + + if _, err := contract.Submit( + "AgreeToTransfer", + client.WithTransient(transient{ + "asset_value": marshal(dataForAgreement), + }), + ); err != nil { + panic(err) + } + + logTxCommitSuccess() +} + +func readTransferAgreement(contract *client.Contract, assetID string) { + fmt.Printf("\n--> Evaluate Transaction: ReadTransferAgreement, ID: %s\n", assetID) + + resultBytes, err := contract.EvaluateTransaction("ReadTransferAgreement", assetID) + if err != nil { + panic(err) + } + + if len(resultBytes) == 0 { + doFail("Received empty result for ReadTransferAgreement") + } + + fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) +} + +func transferAsset(contract *client.Contract, assetID string) (err error) { + fmt.Printf("\n--> Submit Transaction: TransferAsset, ID: %s\n", assetID) + + buyerDetails := struct { + AssetID string `json:"assetID"` + BuyerMSP string `json:"buyerMSP"` + }{assetID, mspIDOrg2} + + if _, err = contract.Submit( + "TransferAsset", + client.WithTransient(transient{ + "asset_owner": marshal(buyerDetails), + }), + ); err != nil { + return + } + + logTxCommitSuccess() + return +} + +func deleteAsset(contract *client.Contract, assetID string) (err error) { + fmt.Printf("\n--> Submit Transaction: DeleteAsset, ID: %s\n", assetID) + + dataForDelete := struct{ AssetID string }{assetID} + + if _, err = contract.Submit( + "DeleteAsset", + client.WithTransient(transient{ + "asset_delete": marshal(dataForDelete), + }), + ); err != nil { + return + } + + logTxCommitSuccess() + return +} + +func purgeAsset(contract *client.Contract, assetID string) (err error) { + fmt.Printf("\n--> Submit Transaction: PurgeAsset, ID: %s\n", assetID) + + dataForPurge := struct{ AssetID string }{assetID} + + if _, err = contract.Submit( + "PurgeAsset", + client.WithTransient(transient{ + "asset_purge": marshal(dataForPurge), + }), + ); err != nil { + return + } + + logTxCommitSuccess() + return +} + +func readAssetPrivateDetails(contract *client.Contract, assetID, collectionName string) bool { + fmt.Printf("\n--> Evaluate Transaction: ReadAssetPrivateDetails from %s, ID: %s\n", collectionName, assetID) + + resultBytes, err := contract.EvaluateTransaction("ReadAssetPrivateDetails", collectionName, assetID) + if err != nil { + panic(err) + } + + if len(resultBytes) == 0 { + fmt.Println("*** No result") + return false + } + + fmt.Printf("*** Result: %s\n", formatJSON(resultBytes)) + + return true +} + +func marshal(value any) []byte { + valueAsBytes, err := json.Marshal(&value) + if err != nil { + panic(err) + } + + return valueAsBytes +} + +func logTxCommitSuccess() { + fmt.Println("*** Transaction committed successfully") +} + +func doFail(msg string) { + fmt.Println(Red + msg + Reset) + panic(errors.New(msg)) +} + +func formatJSON(data []byte) string { + var result bytes.Buffer + if err := json.Indent(&result, data, "", " "); err != nil { + panic(fmt.Errorf("failed to parse JSON: %w", err)) + } + return result.String() +} + +func errorWithDetails(err error) error { + var buf strings.Builder + + statusErr := status.Convert(err) + errDetails := statusErr.Details() + if len(errDetails) > 0 { + buf.WriteString("\nError Details:") + + for _, errDetail := range errDetails { + if detail, ok := errDetail.(*gateway.ErrorDetail); ok { + buf.WriteString(fmt.Sprintf("\n- address: %s", detail.GetAddress())) + buf.WriteString(fmt.Sprintf("\n- mspID: %s", detail.GetMspId())) + buf.WriteString(fmt.Sprintf("\n- message: %s\n", detail.GetMessage())) + } + } + } + + return fmt.Errorf("%w%s", err, buf.String()) +} diff --git a/asset-transfer-private-data/application-gateway-go/connect.go b/asset-transfer-private-data/application-gateway-go/connect.go new file mode 100644 index 0000000000..3bd768634c --- /dev/null +++ b/asset-transfer-private-data/application-gateway-go/connect.go @@ -0,0 +1,111 @@ +/* +Copyright 2022 IBM All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "crypto/x509" + "fmt" + "os" + "path" + + "github.com/hyperledger/fabric-gateway/pkg/identity" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +const ( + cryptoPathOrg1 = "../../test-network/organizations/peerOrganizations/org1.example.com" + keyDirectoryPathOrg1 = cryptoPathOrg1 + "/users/User1@org1.example.com/msp/keystore" + certDirectoryPathOrg1 = cryptoPathOrg1 + "/users/User1@org1.example.com/msp/signcerts" + tlsCertPathOrg1 = cryptoPathOrg1 + "/peers/peer0.org1.example.com/tls/ca.crt" + peerEndpointOrg1 = "dns:///localhost:7051" + peerNameOrg1 = "peer0.org1.example.com" + cryptoPathOrg2 = "../../test-network/organizations/peerOrganizations/org2.example.com" + keyDirectoryPathOrg2 = cryptoPathOrg2 + "/users/User1@org2.example.com/msp/keystore" + certDirectoryPathOrg2 = cryptoPathOrg2 + "/users/User1@org2.example.com/msp/signcerts" + tlsCertPathOrg2 = cryptoPathOrg2 + "/peers/peer0.org2.example.com/tls/ca.crt" + peerEndpointOrg2 = "dns:///localhost:9051" + peerNameOrg2 = "peer0.org2.example.com" +) + +// newGrpcConnection creates a gRPC connection to the Gateway server. +func newGrpcConnection(tlsCertPath, peerEndpoint, peerName string) *grpc.ClientConn { + certificatePEM, err := os.ReadFile(tlsCertPath) + if err != nil { + panic(fmt.Errorf("failed to read TLS certificate file: %w", err)) + } + + certificate, err := identity.CertificateFromPEM(certificatePEM) + if err != nil { + panic(err) + } + + certPool := x509.NewCertPool() + certPool.AddCert(certificate) + transportCredentials := credentials.NewClientTLSFromCert(certPool, peerName) + + connection, err := grpc.NewClient(peerEndpoint, grpc.WithTransportCredentials(transportCredentials)) + if err != nil { + panic(fmt.Errorf("failed to create gRPC connection: %w", err)) + } + + return connection +} + +// newIdentity creates a client identity for this Gateway connection using an X.509 certificate. +func newIdentity(certDirectoryPath, mspId string) *identity.X509Identity { + certificatePEM, err := readFirstFile(certDirectoryPath) + if err != nil { + panic(fmt.Errorf("failed to read certificate file: %w", err)) + } + + certificate, err := identity.CertificateFromPEM(certificatePEM) + if err != nil { + panic(err) + } + + id, err := identity.NewX509Identity(mspId, certificate) + if err != nil { + panic(err) + } + + return id +} + +// newSign creates a function that generates a digital signature from a message digest using a private key. +func newSign(keyDirectoryPash string) identity.Sign { + privateKeyPEM, err := readFirstFile(keyDirectoryPash) + if err != nil { + panic(fmt.Errorf("failed to read private key file: %w", err)) + } + + privateKey, err := identity.PrivateKeyFromPEM(privateKeyPEM) + if err != nil { + panic(err) + } + + sign, err := identity.NewPrivateKeySign(privateKey) + if err != nil { + panic(err) + } + + return sign +} + +func readFirstFile(dirPath string) ([]byte, error) { + dir, err := os.Open(dirPath) + if err != nil { + return nil, err + } + + fileNames, err := dir.Readdirnames(1) + if err != nil { + return nil, err + } + + return os.ReadFile(path.Join(dirPath, fileNames[0])) +} diff --git a/asset-transfer-private-data/application-gateway-go/go.mod b/asset-transfer-private-data/application-gateway-go/go.mod new file mode 100644 index 0000000000..83a97113ba --- /dev/null +++ b/asset-transfer-private-data/application-gateway-go/go.mod @@ -0,0 +1,23 @@ +module assetTransfer + +go 1.22.0 + +require ( + github.com/hyperledger/fabric-gateway v1.6.0 + google.golang.org/grpc v1.67.0 +) + +require ( + github.com/golang/protobuf v1.5.3 // indirect + github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 // indirect + github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 // indirect + github.com/hyperledger/fabric-sdk-go v1.0.0 // indirect + github.com/miekg/pkcs11 v1.1.1 // indirect + github.com/pkg/errors v0.8.1 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) diff --git a/asset-transfer-private-data/application-gateway-go/go.sum b/asset-transfer-private-data/application-gateway-go/go.sum new file mode 100644 index 0000000000..5306d77ec4 --- /dev/null +++ b/asset-transfer-private-data/application-gateway-go/go.sum @@ -0,0 +1,223 @@ +bitbucket.org/liamstask/goose v0.0.0-20150115234039-8488cc47d90c/go.mod h1:hSVuE3qU7grINVSwrmzHfpg9k87ALBk+XaualNyUzI4= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= +github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/backoff v0.0.0-20161212185259-647f3cdfc87a/go.mod h1:rzgs2ZOiguV6/NpiDgADjRLPNyZlApIWxKpkT+X8SdY= +github.com/cloudflare/cfssl v1.4.1/go.mod h1:KManx/OJPb5QY+y0+o/898AMcM128sF0bURvoVUSjTo= +github.com/cloudflare/go-metrics v0.0.0-20151117154305-6a9aea36fb41/go.mod h1:eaZPlJWD+G9wseg1BuRXlHnjntPMrywMsyxf+LTOdP4= +github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6Se34jNoqrd8bTxrmJB2Bg2aoZ2CdSXonils9NsiNgo= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/getsentry/raven-go v0.0.0-20180121060056-563b81fc02b7/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hyperledger/fabric-config v0.0.5/go.mod h1:YpITBI/+ZayA3XWY5lF302K7PAsFYjEEPM/zr3hegA8= +github.com/hyperledger/fabric-gateway v1.6.0 h1:mPdXFSHdEjT0cmhsqKBfFMTVyBvfJXlO3Neicp/c27E= +github.com/hyperledger/fabric-gateway v1.6.0/go.mod h1:qHdJcgC6UrTxfYH+YIyAhPUkeNri0gPpyP/6xmiYrZo= +github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= +github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23 h1:SEbB3yH4ISTGRifDamYXAst36gO2kM855ndMJlsv+pc= +github.com/hyperledger/fabric-protos-go v0.0.0-20200707132912-fee30f3ccd23/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3 h1:Xpd6fzG/KjAOHJsq7EQXY2l+qi/y8muxBaY7R6QWABk= +github.com/hyperledger/fabric-protos-go-apiv2 v0.3.3/go.mod h1:2pq0ui6ZWA0cC8J+eCErgnMDCS1kPOEYVY+06ZAK0qE= +github.com/hyperledger/fabric-sdk-go v1.0.0 h1:NRu0iNbHV6u4nd9jgYghAdA1Ll4g0Sri4hwMEGiTbyg= +github.com/hyperledger/fabric-sdk-go v1.0.0/go.mod h1:qWE9Syfg1KbwNjtILk70bJLilnmCvllIYFCSY/pa1RU= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmhodges/clock v0.0.0-20160418191101-880ee4c33548/go.mod h1:hGT6jSUVzF6no3QaDSMLGLEHtHSBSefs+MgcDWnmhmo= +github.com/jmoiron/sqlx v0.0.0-20180124204410-05cef0741ade/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/sqlstruct v0.0.0-20150923205031-648daed35d49/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE= +github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A/yNRw= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/go-gypsy v0.0.0-20160905020020-08cad365cd28/go.mod h1:T/T7jsxVqf9k/zYOqbgNAsANsjxTd1Yq3htjDhQ1H0c= +github.com/lib/pq v0.0.0-20180201184707-88edab080323/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/spf13/afero v1.3.1/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.1.1/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/weppos/publicsuffix-go v0.5.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= +github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= +github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= +github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e/go.mod h1:w7kd3qXHh8FNaczNjslXqvFQiv5mMWRXlL9klTUAHc8= +github.com/zmap/zlint v0.0.0-20190806154020-fd021b4cfbeb/go.mod h1:29UiAJNsiVdvTBFCJW8e3q6dcDbOoPkhMgttOSCIMMY= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61 h1:N9BgCIAUvn/M+p4NJccWPWb3BWh88+zyL0ll9HgbEeM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240924160255-9d4c2d233b61/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/asset-transfer-private-data/application-gateway-typescript/src/app.ts b/asset-transfer-private-data/application-gateway-typescript/src/app.ts index ffa5423905..1e190227f1 100644 --- a/asset-transfer-private-data/application-gateway-typescript/src/app.ts +++ b/asset-transfer-private-data/application-gateway-typescript/src/app.ts @@ -18,14 +18,14 @@ const mspIdOrg2 = 'Org2MSP'; const utf8Decoder = new TextDecoder(); -// Collection Names +// Collection names. const org1PrivateCollectionName = 'Org1MSPPrivateCollection'; const org2PrivateCollectionName = 'Org2MSPPrivateCollection'; const RED = '\x1b[31m\n'; const RESET = '\x1b[0m'; -// Use a unique key so that we can run multiple times +// Use a unique key so that we can run multiple times. const now = Date.now(); const assetID1 = `asset${String(now)}`; const assetID2 = `asset${String(now + 1)}`; @@ -74,10 +74,10 @@ async function main(): Promise { await createAssets(contractOrg1); // Read asset from the Org1's private data collection with ID in the given range. - await getAssetsByRange(contractOrg1); + await getAssetByRange(contractOrg1); try { - // Attempt to transfer asset without prior aprroval from Org2, transaction expected to fail. + // Attempt to transfer asset without prior approval from Org2, transaction expected to fail. console.log('\nAttempt TransferAsset without prior AgreeToTransfer'); await transferAsset(contractOrg1, assetID1); doFail('TransferAsset transaction succeeded when it was expected to fail'); @@ -101,7 +101,7 @@ async function main(): Promise { // Transfer asset to Org2. await transferAsset(contractOrg1, assetID1); - // Again ReadAsset : results will show that the buyer identity now owns the asset. + // Again ReadAsset: results will show that the buyer identity now owns the asset. await readAssetByID(contractOrg1, assetID1); // Confirm that transfer removed the private details from the Org1 collection. @@ -112,7 +112,7 @@ async function main(): Promise { console.log('\n~~~~~~~~~~~~~~~~ As Org2 Client ~~~~~~~~~~~~~~~~'); - // Org2 can read asset private details: Org2 is owner, and private details exist in new owner's Collection + // Org2 can read asset private details: Org2 is owner, and private details exist in new owner's collection. const org2ReadSuccess = await readAssetPrivateDetails(contractOrg2, assetID1, org2PrivateCollectionName); if (!org2ReadSuccess) { doFail(`Asset private data not found in ${org2PrivateCollectionName}`); @@ -131,8 +131,8 @@ async function main(): Promise { // Delete AssetID2 as Org1. await deleteAsset(contractOrg1, assetID2); - // Trigger a purge of the private data for the asset - // The previous delete is optinal if purge is used + // Trigger a purge of the private data for the asset. + // The previous delete is optional if purge is used. await purgeAsset(contractOrg1, assetID2); } finally { gatewayOrg1.close(); @@ -186,9 +186,9 @@ async function createAssets(contract: Contract): Promise { console.log('*** Transaction committed successfully'); } -async function getAssetsByRange(contract: Contract): Promise { +async function getAssetByRange(contract: Contract): Promise { // GetAssetByRange returns assets on the ledger with ID in the range of startKey (inclusive) and endKey (exclusive). - console.log(`\n--> Evaluate Transaction: ReadAssetPrivateDetails from ${org1PrivateCollectionName}`); + console.log(`\n--> Evaluate Transaction: GetAssetByRange from ${org1PrivateCollectionName}`); const resultBytes = await contract.evaluateTransaction( 'GetAssetByRange', @@ -198,7 +198,7 @@ async function getAssetsByRange(contract: Contract): Promise { const resultString = utf8Decoder.decode(resultBytes); if (!resultString) { - doFail('Received empty query list for readAssetPrivateDetailsOrg1'); + doFail('Received empty query list for GetAssetByRange'); } const result: unknown = JSON.parse(resultString); console.log('*** Result:', result); @@ -217,8 +217,8 @@ async function readAssetByID(contract: Contract, assetID: string): Promise } async function agreeToTransfer(contract: Contract, assetID: string): Promise { - // Buyer from Org2 agrees to buy the asset// - // To purchase the asset, the buyer needs to agree to the same value as the asset owner + // Buyer from Org2 agrees to buy the asset. + // To purchase the asset, the buyer needs to agree to the same value as the asset owner. const dataForAgreement = { assetID, appraisedValue: 100 }; console.log('\n--> Submit Transaction: AgreeToTransfer, payload:', dataForAgreement); diff --git a/ci/scripts/run-test-network-private.sh b/ci/scripts/run-test-network-private.sh index c973409b82..914c94ba4b 100755 --- a/ci/scripts/run-test-network-private.sh +++ b/ci/scripts/run-test-network-private.sh @@ -34,3 +34,12 @@ print "Start application" npm start popd stopNetwork + +# Run Go gateway application +createNetwork +print "Initializing Go gateway application" +pushd ../asset-transfer-private-data/application-gateway-go +print "Executing application" +go run . +popd +stopNetwork