Skip to content

Commit

Permalink
[FAB-3073] SDK Go - Move utility functions
Browse files Browse the repository at this point in the history
Change-Id: I060f1423465a8568ddbbad425bb54a8e4bc2197d
Signed-off-by: Sandra Vrtikapa <[email protected]>
  • Loading branch information
sandrask committed Apr 12, 2017
1 parent c47bbf2 commit 7a66106
Show file tree
Hide file tree
Showing 11 changed files with 518 additions and 425 deletions.
7 changes: 6 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type PeerConfig struct {
EventPort string
TLSCertificate string
TLSServerHostOverride string
Primary bool
}

var myViper = viper.New()
Expand Down Expand Up @@ -127,13 +128,16 @@ func GetPeersConfig() []PeerConfig {
mm, ok := value.(map[string]interface{})
var host string
var port int
var primary bool
var eventHost string
var eventPort int
var tlsCertificate string
var tlsServerHostOverride string

if ok {
host, _ = mm["host"].(string)
port, _ = mm["port"].(int)
primary, _ = mm["primary"].(bool)
eventHost, _ = mm["event_host"].(string)
eventPort, _ = mm["event_port"].(int)
tlsCertificate, _ = mm["tls"].(map[string]interface{})["certificate"].(string)
Expand All @@ -143,6 +147,7 @@ func GetPeersConfig() []PeerConfig {
mm1 := value.(map[interface{}]interface{})
host, _ = mm1["host"].(string)
port, _ = mm1["port"].(int)
primary, _ = mm1["primary"].(bool)
eventHost, _ = mm1["event_host"].(string)
eventPort, _ = mm1["event_port"].(int)
tlsCertificate, _ = mm1["tls"].(map[string]interface{})["certificate"].(string)
Expand All @@ -151,7 +156,7 @@ func GetPeersConfig() []PeerConfig {
}

p := PeerConfig{Host: host, Port: strconv.Itoa(port), EventHost: eventHost, EventPort: strconv.Itoa(eventPort),
TLSCertificate: tlsCertificate, TLSServerHostOverride: tlsServerHostOverride}
TLSCertificate: tlsCertificate, TLSServerHostOverride: tlsServerHostOverride, Primary: primary}
if p.Host == "" {
panic(fmt.Sprintf("host key not exist or empty for %s", key))
}
Expand Down
207 changes: 207 additions & 0 deletions fabric-client/helpers/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package helpers

import (
"fmt"
"io/ioutil"
"math/rand"
"os"
"time"

"github.com/hyperledger/fabric-sdk-go/config"

fabricClient "github.com/hyperledger/fabric-sdk-go/fabric-client"
"github.com/hyperledger/fabric-sdk-go/fabric-client/events"
"github.com/hyperledger/fabric-sdk-go/fabric-client/util"
"github.com/op/go-logging"
)

var origGoPath = os.Getenv("GOPATH")
var logger = logging.MustGetLogger("fabric_sdk_go")

// GetChain initializes and returns a chain based on config
func GetChain(client fabricClient.Client, chainID string) (fabricClient.Chain, error) {

chain, err := client.NewChain(chainID)
if err != nil {
return nil, fmt.Errorf("NewChain return error: %v", err)
}
orderer, err := fabricClient.CreateNewOrderer(fmt.Sprintf("%s:%s", config.GetOrdererHost(), config.GetOrdererPort()),
config.GetOrdererTLSCertificate(), config.GetOrdererTLSServerHostOverride())
if err != nil {
return nil, fmt.Errorf("CreateNewOrderer return error: %v", err)
}
chain.AddOrderer(orderer)

for _, p := range config.GetPeersConfig() {
endorser, err := fabricClient.CreateNewPeer(fmt.Sprintf("%s:%s", p.Host, p.Port), p.TLSCertificate, p.TLSServerHostOverride)
if err != nil {
return nil, fmt.Errorf("CreateNewPeer return error: %v", err)
}
chain.AddPeer(endorser)
if p.Primary {
chain.SetPrimaryPeer(endorser)
}
}

return chain, nil
}

// SendInstallCC Sends an install proposal to one or more endorsing peers.
func SendInstallCC(chain fabricClient.Chain, chainCodeID string, chainCodePath string, chainCodeVersion string, chaincodePackage []byte, targets []fabricClient.Peer, deployPath string) error {
ChangeGOPATHToDeploy(deployPath)
transactionProposalResponse, _, err := chain.SendInstallProposal(chainCodeID, chainCodePath, chainCodeVersion, chaincodePackage, targets)
ResetGOPATH()

if err != nil {
return fmt.Errorf("SendInstallProposal return error: %v", err)
}

for _, v := range transactionProposalResponse {
if v.Err != nil {
return fmt.Errorf("SendInstallProposal Endorser %s return error: %v", v.Endorser, v.Err)
}
logger.Debugf("SendInstallProposal Endorser '%s' return ProposalResponse status:%v\n", v.Endorser, v.Status)
}

return nil

}

// SendInstantiateCC Sends instantiate CC proposal to one or more endorsing peers
func SendInstantiateCC(chain fabricClient.Chain, chainCodeID string, chainID string, args []string, chaincodePath string, chaincodeVersion string, targets []fabricClient.Peer, eventHub events.EventHub) error {

transactionProposalResponse, txID, err := chain.SendInstantiateProposal(chainCodeID, chainID, args, chaincodePath, chaincodeVersion, targets)
if err != nil {
return fmt.Errorf("SendInstantiateProposal return error: %v", err)
}

for _, v := range transactionProposalResponse {
if v.Err != nil {
return fmt.Errorf("SendInstantiateProposal Endorser %s return error: %v", v.Endorser, v.Err)
}
logger.Debug("SendInstantiateProposal Endorser '%s' return ProposalResponse status:%v\n", v.Endorser, v.Status)
}

// Register for commit event
done, fail := RegisterTxEvent(txID, eventHub)

if _, err = CreateAndSendTransaction(chain, transactionProposalResponse); err != nil {
return fmt.Errorf("CreateTransaction return error: %v", err)
}

select {
case <-done:
case <-fail:
return fmt.Errorf("instantiateCC Error received from eventhub for txid(%s) error(%v)", txID, fail)
case <-time.After(time.Second * 30):
return fmt.Errorf("instantiateCC Didn't receive block event for txid(%s)", txID)
}
return nil

}

// CreateAndJoinChannel creates the channel represented by this chain
// and makes the primary peer join it. It reads channel configuration from tx channelConfig file
func CreateAndJoinChannel(client fabricClient.Client, chain fabricClient.Chain, channelConfig string) error {

// Check if primary peer has joined this channel
var foundChannel bool
primaryPeer := chain.GetPrimaryPeer()
response, err := chain.QueryChannels(primaryPeer)
if err != nil {
return fmt.Errorf("Error querying channels for primary peer: %s", err)
}
for _, channel := range response.Channels {
if channel.ChannelId == chain.GetName() {
foundChannel = true
}
}

if foundChannel {
// There's no need to create a channel, return
return nil
}

logger.Infof("***** Creating and Joining channel: %s *****\n", chain.GetName())

configTx, err := ioutil.ReadFile(channelConfig)
if err != nil {
return fmt.Errorf("Error reading config file: %v", err)
}

request := fabricClient.CreateChannelRequest{ConfigData: configTx}
if err = chain.CreateChannel(&request); err != nil {
return err
}

// Wait for orderer to process channel metadata
time.Sleep(time.Second * 2)
// Test join channel
creator, err := getCreatorID(client)
if err != nil {
return fmt.Errorf("Could not generate creator ID: %v", err)
}
nonce, err := util.GenerateRandomNonce()
if err != nil {
return fmt.Errorf("Could not compute nonce: %s", err)
}
txID, err := util.ComputeTxID(nonce, creator)
if err != nil {
return fmt.Errorf("Could not compute TxID: %s", err)
}

req := &fabricClient.JoinChannelRequest{
Targets: []fabricClient.Peer{chain.GetPrimaryPeer()}, TxID: txID, Nonce: nonce}
if err = chain.JoinChannel(req); err != nil {
return err
}

logger.Infof("***** Created and Joined channel: %s *****\n", chain.GetName())

return nil
}

// Utility to create random string of strlen length
func randomString(strlen int) string {
const chars = "abcdefghijklmnopqrstuvwxyz0123456789"
result := make([]byte, strlen)
for i := 0; i < strlen; i++ {
result[i] = chars[rand.Intn(len(chars))]
}
return string(result)
}

// ChangeGOPATHToDeploy changes go path to fixtures folder
func ChangeGOPATHToDeploy(deployPath string) {
os.Setenv("GOPATH", deployPath)
}

// ResetGOPATH resets go path to original
func ResetGOPATH() {
os.Setenv("GOPATH", origGoPath)
}

// GenerateRandomID generates random ID
func GenerateRandomID() string {
rand.Seed(time.Now().UnixNano())
return randomString(10)
}
92 changes: 62 additions & 30 deletions test/integration/util.go → fabric-client/helpers/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package integration
package helpers

import (
"encoding/pem"
"fmt"
"time"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-sdk-go/config"
fabricClient "github.com/hyperledger/fabric-sdk-go/fabric-client"
"github.com/hyperledger/fabric-sdk-go/fabric-client/events"
"github.com/hyperledger/fabric/bccsp"
"github.com/hyperledger/fabric/msp"

fabricCAClient "github.com/hyperledger/fabric-sdk-go/fabric-ca-client"

kvs "github.com/hyperledger/fabric-sdk-go/fabric-client/keyvaluestore"
bccspFactory "github.com/hyperledger/fabric/bccsp/factory"
)

// CreateAndSendTransactionProposal combines create and send transaction proposal methods into one method.
Expand All @@ -45,7 +53,7 @@ func CreateAndSendTransactionProposal(chain fabricClient.Chain, chainCodeID stri
if v.Err != nil {
return nil, signedProposal.TransactionID, fmt.Errorf("invoke Endorser %s return error: %v", v.Endorser, v.Err)
}
fmt.Printf("invoke Endorser '%s' return ProposalResponse status:%v\n", v.Endorser, v.Status)
logger.Debugf("invoke Endorser '%s' return ProposalResponse status:%v\n", v.Endorser, v.Status)
}

return transactionProposalResponses, signedProposal.TransactionID, nil
Expand Down Expand Up @@ -74,37 +82,61 @@ func CreateAndSendTransaction(chain fabricClient.Chain, resps []*fabricClient.Tr
return transactionResponse, nil
}

// RegisterEvent registers on the given eventhub for the give transaction
// returns a boolean channel which receives true when the event is complete
// and an error channel for errors
func RegisterEvent(txID string, eventHub events.EventHub) (chan bool, chan error) {
done := make(chan bool)
fail := make(chan error)
// GetClient initializes and returns a client based on config and user
func GetClient(name string, pwd string, stateStorePath string) (fabricClient.Client, error) {
client := fabricClient.NewClient()

cryptoSuite := bccspFactory.GetDefault()

eventHub.RegisterTxEvent(txID, func(txId string, err error) {
client.SetCryptoSuite(cryptoSuite)
stateStore, err := kvs.CreateNewFileKeyValueStore(stateStorePath)
if err != nil {
return nil, fmt.Errorf("CreateNewFileKeyValueStore return error[%s]", err)
}
client.SetStateStore(stateStore)
user, err := client.GetUserContext(name)
if err != nil {
return nil, fmt.Errorf("client.GetUserContext return error: %v", err)
}
if user == nil {
fabricCAClient, err1 := fabricCAClient.NewFabricCAClient()
if err1 != nil {
return nil, fmt.Errorf("NewFabricCAClient return error: %v", err)
}
key, cert, err1 := fabricCAClient.Enroll(name, pwd)
keyPem, _ := pem.Decode(key)
if err1 != nil {
return nil, fmt.Errorf("Enroll return error: %v", err1)
}
user := fabricClient.NewUser(name)
k, err1 := client.GetCryptoSuite().KeyImport(keyPem.Bytes, &bccsp.ECDSAPrivateKeyImportOpts{Temporary: false})
if err1 != nil {
return nil, fmt.Errorf("KeyImport return error: %v", err)
}
user.SetPrivateKey(k)
user.SetEnrollmentCertificate(cert)
err = client.SetUserContext(user, false)
if err != nil {
fmt.Printf("Received error event for txid(%s)\n", txId)
fail <- err
} else {
fmt.Printf("Received success event for txid(%s)\n", txId)
done <- true
return nil, fmt.Errorf("client.SetUserContext return error: %v", err)
}
})
}

return done, fail
}
return client, nil

// RegisterCCEvent registers chain code event on the given eventhub
// @returns {chan bool} channel which receives true when the event is complete
// @returns {object} ChainCodeCBE object handle that should be used to unregister
func RegisterCCEvent(chainCodeID, eventID string, eventHub events.EventHub) (chan bool, *events.ChainCodeCBE) {
done := make(chan bool)
}

// Register callback for CE
rce := eventHub.RegisterChaincodeEvent(chainCodeID, eventID, func(ce *events.ChaincodeEvent) {
fmt.Printf("Received CC event ( %s ): \n%v\n", time.Now().Format(time.RFC850), ce)
done <- true
})
// Utility method gets serialized enrollment certificate
func getCreatorID(client fabricClient.Client) ([]byte, error) {

return done, rce
user, err := client.GetUserContext("")
if err != nil {
return nil, fmt.Errorf("GetUserContext returned error: %s", err)
}
serializedIdentity := &msp.SerializedIdentity{Mspid: config.GetFabricCAID(),
IdBytes: user.GetEnrollmentCertificate()}
creatorID, err := proto.Marshal(serializedIdentity)
if err != nil {
return nil, fmt.Errorf("Could not Marshal serializedIdentity, err %s", err)
}
return creatorID, nil
}
Loading

0 comments on commit 7a66106

Please sign in to comment.