diff --git a/ci/templates/fabcar/azure-pipelines-go.yml b/ci/templates/fabcar/azure-pipelines-go.yml index 8d53e69b..6e1562c6 100644 --- a/ci/templates/fabcar/azure-pipelines-go.yml +++ b/ci/templates/fabcar/azure-pipelines-go.yml @@ -6,3 +6,16 @@ steps: - script: ./startFabric.sh go workingDirectory: fabcar displayName: Start Fabric + - task: GoTool@0 + displayName: 'Use Go 1.14.2' + inputs: + version: '1.14.2' + - task: Go@0 + displayName: 'go build' + inputs: + command: build + arguments: '-o "fabcar"' + workingDirectory: fabcar/go + - script: DISCOVERY_AS_LOCALHOST=TRUE ./fabcar + workingDirectory: fabcar/go + displayName: Run FabCar Application diff --git a/fabcar/go/.gitignore b/fabcar/go/.gitignore new file mode 100755 index 00000000..076e1bea --- /dev/null +++ b/fabcar/go/.gitignore @@ -0,0 +1,2 @@ +wallet +!wallet/.gitkeep \ No newline at end of file diff --git a/fabcar/go/fabcar.go b/fabcar/go/fabcar.go new file mode 100644 index 00000000..f75c6dd3 --- /dev/null +++ b/fabcar/go/fabcar.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 IBM All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package main + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/hyperledger/fabric-sdk-go/pkg/core/config" + "github.com/hyperledger/fabric-sdk-go/pkg/gateway" +) + +func main() { + wallet, err := gateway.NewFileSystemWallet("wallet") + if err != nil { + fmt.Printf("Failed to create wallet: %s\n", err) + os.Exit(1) + } + + if !wallet.Exists("appUser") { + err = populateWallet(wallet) + if err != nil { + fmt.Printf("Failed to populate wallet contents: %s\n", err) + os.Exit(1) + } + } + + ccpPath := filepath.Join( + "..", + "..", + "test-network", + "organizations", + "peerOrganizations", + "org1.example.com", + "connection-org1.yaml", + ) + + gw, err := gateway.Connect( + gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))), + gateway.WithIdentity(wallet, "appUser"), + ) + if err != nil { + fmt.Printf("Failed to connect to gateway: %s\n", err) + os.Exit(1) + } + defer gw.Close() + + network, err := gw.GetNetwork("mychannel") + if err != nil { + fmt.Printf("Failed to get network: %s\n", err) + os.Exit(1) + } + + contract := network.GetContract("fabcar") + + result, err := contract.EvaluateTransaction("queryAllCars") + if err != nil { + fmt.Printf("Failed to evaluate transaction: %s\n", err) + os.Exit(1) + } + fmt.Println(string(result)) + + result, err = contract.SubmitTransaction("createCar", "CAR10", "VW", "Polo", "Grey", "Mary") + if err != nil { + fmt.Printf("Failed to submit transaction: %s\n", err) + os.Exit(1) + } + fmt.Println(string(result)) + + result, err = contract.EvaluateTransaction("queryCar", "CAR10") + if err != nil { + fmt.Printf("Failed to evaluate transaction: %s\n", err) + os.Exit(1) + } + fmt.Println(string(result)) + + _, err = contract.SubmitTransaction("changeCarOwner", "CAR10", "Archie") + if err != nil { + fmt.Printf("Failed to submit transaction: %s\n", err) + os.Exit(1) + } + + result, err = contract.EvaluateTransaction("queryCar", "CAR10") + if err != nil { + fmt.Printf("Failed to evaluate transaction: %s\n", err) + os.Exit(1) + } + fmt.Println(string(result)) +} + +func populateWallet(wallet *gateway.Wallet) error { + credPath := filepath.Join( + "..", + "..", + "test-network", + "organizations", + "peerOrganizations", + "org1.example.com", + "users", + "User1@org1.example.com", + "msp", + ) + + certPath := filepath.Join(credPath, "signcerts", "cert.pem") + // read the certificate pem + cert, err := ioutil.ReadFile(filepath.Clean(certPath)) + if err != nil { + return err + } + + keyDir := filepath.Join(credPath, "keystore") + // there's a single file in this dir containing the private key + files, err := ioutil.ReadDir(keyDir) + if err != nil { + return err + } + if len(files) != 1 { + return errors.New("keystore folder should have contain one file") + } + keyPath := filepath.Join(keyDir, files[0].Name()) + key, err := ioutil.ReadFile(filepath.Clean(keyPath)) + if err != nil { + return err + } + + identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key)) + + err = wallet.Put("appUser", identity) + if err != nil { + return err + } + return nil +} diff --git a/fabcar/go/go.mod b/fabcar/go/go.mod new file mode 100644 index 00000000..e2531738 --- /dev/null +++ b/fabcar/go/go.mod @@ -0,0 +1,5 @@ +module fabcar + +go 1.14 + +require github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f // indirect diff --git a/fabcar/go/go.sum b/fabcar/go/go.sum new file mode 100644 index 00000000..c4845790 --- /dev/null +++ b/fabcar/go/go.sum @@ -0,0 +1,87 @@ +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/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/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +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.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/certificate-transparency-go v0.0.0-20180222191210-5ab67e519c93/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/hashicorp/hcl v0.0.0-20180404174102-ef8a98b0bbce/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= +github.com/hyperledger/fabric-protos-go v0.0.0-20191121202242-f5500d5e3e85/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= +github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f h1:eAkJx0+8PBbfP6xZxVRD2agk9W7oDbqllxO+ERgnKJk= +github.com/hyperledger/fabric-sdk-go v1.0.0-beta1.0.20200526155846-219a09aadc0f/go.mod h1:/s224b8NLvOJOCIqBvWd9O6u7GE33iuIOT6OfcTE1OE= +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/magiconair/properties v1.7.6/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/pkcs11 v0.0.0-20190329070431-55f3fac3af27/go.mod h1:WCBAbTOdfhHhz7YXujeZMF7owC4tPb1naKFsgfUISjo= +github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/pelletier/go-toml v1.1.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180705121852-ae68e2d4c00f/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/spf13/afero v1.1.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/jwalterweatherman v0.0.0-20180109140146-7c0cea34c8ec/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.0.2/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +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/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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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-20190227155943-e225da77a7e6/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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +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-20190327125643-d831d65fe17d/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +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= +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= diff --git a/fabcar/startFabric.sh b/fabcar/startFabric.sh index 386ff788..5f1452cd 100755 --- a/fabcar/startFabric.sh +++ b/fabcar/startFabric.sh @@ -25,6 +25,7 @@ fi rm -rf javascript/wallet/* rm -rf java/wallet/* rm -rf typescript/wallet/* +rm -rf go/wallet/* # launch network; create channel and join peer to channel pushd ../test-network @@ -103,4 +104,19 @@ Java: - Submit a transaction to change the owner of this car - Evaluate a transaction (query) to return the updated details of this car +Go: + + Start by changing into the "go" directory: + cd go + + Then, install dependencies and run the test using: + go run fabcar.go + + The test will invoke the sample client app which perform the following: + - Import user credentials into the wallet (if they don't already exist there) + - Submit a transaction to create a new car + - Evaluate a transaction (query) to return details of this car + - Submit a transaction to change the owner of this car + - Evaluate a transaction (query) to return the updated details of this car + EOF diff --git a/test-network/organizations/ccp-generate.sh b/test-network/organizations/ccp-generate.sh index 40f52395..7e091d0b 100755 --- a/test-network/organizations/ccp-generate.sh +++ b/test-network/organizations/ccp-generate.sh @@ -23,7 +23,7 @@ function yaml_ccp { -e "s/\${CAPORT}/$3/" \ -e "s#\${PEERPEM}#$PP#" \ -e "s#\${CAPEM}#$CP#" \ - organizations/ccp-template.yaml | sed -e $'s/\\\\n/\\\n /g' + organizations/ccp-template.yaml | sed -e $'s/\\\\n/\\\n /g' } ORG=1 diff --git a/test-network/organizations/ccp-template.json b/test-network/organizations/ccp-template.json index 2b19d1b9..e945bfe9 100755 --- a/test-network/organizations/ccp-template.json +++ b/test-network/organizations/ccp-template.json @@ -39,7 +39,7 @@ "url": "https://localhost:${CAPORT}", "caName": "ca-org${ORG}", "tlsCACerts": { - "pem": "${CAPEM}" + "pem": ["${CAPEM}"] }, "httpOptions": { "verify": false diff --git a/test-network/organizations/ccp-template.yaml b/test-network/organizations/ccp-template.yaml index 7e65965f..b675c186 100755 --- a/test-network/organizations/ccp-template.yaml +++ b/test-network/organizations/ccp-template.yaml @@ -19,7 +19,7 @@ peers: url: grpcs://localhost:${P0PORT} tlsCACerts: pem: | - ${PEERPEM} + ${PEERPEM} grpcOptions: ssl-target-name-override: peer0.org${ORG}.example.com hostnameOverride: peer0.org${ORG}.example.com @@ -28,7 +28,8 @@ certificateAuthorities: url: https://localhost:${CAPORT} caName: ca-org${ORG} tlsCACerts: - pem: | - ${CAPEM} + pem: + - | + ${CAPEM} httpOptions: verify: false