From 9b8d2c0927a8618b1f952ae03cd8d1371145da65 Mon Sep 17 00:00:00 2001 From: Divyank Katira Date: Tue, 28 Mar 2017 17:48:52 -0400 Subject: [PATCH] [FAB-2899] Added create channel functionality Change-Id: Ib0d42f86de45f893124a076e740237b9bfa6efed Signed-off-by: Divyank Katira --- config/config.go | 2 +- fabric-ca-client/fabricca.go | 5 +- fabric-client/chain.go | 58 ++++++++++++++---- fabric-client/chain_test.go | 27 ++++++++ fabric-client/orderer_test.go | 2 +- test/fixtures/channel/configtx.yaml | 40 ++++++------ .../channel/{mychannel.tx => testchannel.tx} | Bin 9805 -> 9841 bytes test/fixtures/docker-compose.yaml | 8 --- test/integration/chain_queries_test.go | 2 +- test/integration/channel_test.go | 55 +++++++++++++++++ test/integration/install_chaincode_test.go | 7 ++- 11 files changed, 159 insertions(+), 47 deletions(-) rename test/fixtures/channel/{mychannel.tx => testchannel.tx} (95%) create mode 100644 test/integration/channel_test.go diff --git a/config/config.go b/config/config.go index 98b074d470..07a380df8f 100644 --- a/config/config.go +++ b/config/config.go @@ -55,7 +55,7 @@ type fabricCAConfig struct { var myViper = viper.New() var log = logging.MustGetLogger("fabric_sdk_go") var format = logging.MustStringFormatter( - `%{color}%{time:15:04:05.000} [%{module}] %{level:.4s} : %{message}`, + `%{color}%{time:15:04:05.000} [%{module}] %{level:.4s} : %{color:reset} %{message}`, ) // InitConfig ... diff --git a/fabric-ca-client/fabricca.go b/fabric-ca-client/fabricca.go index 38588896af..0dc021735c 100644 --- a/fabric-ca-client/fabricca.go +++ b/fabric-ca-client/fabricca.go @@ -44,6 +44,7 @@ type services struct { fabricCAClient *fabric_ca.Client } +// RegistrationRequest defines the attributes required to register a user with the CA type RegistrationRequest struct { // Name is the unique name of the identity Name string @@ -58,6 +59,7 @@ type RegistrationRequest struct { Attributes []Attribute } +// RevocationRequest defines the attributes required to revoke credentials with the CA type RevocationRequest struct { // Name of the identity whose certificates should be revoked // If this field is omitted, then Serial and AKI must be specified. @@ -72,6 +74,7 @@ type RevocationRequest struct { Reason int } +// Attribute defines additional attributes that may be passed along during registration type Attribute struct { Key string Value string @@ -144,7 +147,7 @@ func (fabricCAServices *services) Register(registrar fabricclient.User, } // Contruct request for Fabric CA client var attributes []api.Attribute - for i, _ := range request.Attributes { + for i := range request.Attributes { attributes = append(attributes, api.Attribute{Name: request. Attributes[i].Key, Value: request.Attributes[i].Value}) } diff --git a/fabric-client/chain.go b/fabric-client/chain.go index bc1585ce96..5080c5eba6 100644 --- a/fabric-client/chain.go +++ b/fabric-client/chain.go @@ -63,7 +63,7 @@ type Chain interface { AddOrderer(orderer Orderer) RemoveOrderer(orderer Orderer) GetOrderers() []Orderer - InitializeChain() bool + CreateChannel(request CreateChannelRequest) error UpdateChain() bool IsReadonly() bool QueryInfo() (*common.BlockchainInfo, error) @@ -138,6 +138,12 @@ type SignedEnvelope struct { signature []byte } +// CreateChannelRequest requests channel creation on the network +type CreateChannelRequest struct { + // Contains channel configuration (ConfigTx) + ConfigData []byte +} + // NewChain ... /** * @param {string} name to identify different chain instances. The naming of chain instances @@ -335,17 +341,45 @@ func (c *chain) GetOrderers() []Orderer { return orderersArray } -// InitializeChain ... -/** - * Calls the orderer(s) to start building the new chain, which is a combination - * of opening new message stream and connecting the list of participating peers. - * This is a long-running process. Only one of the application instances needs - * to call this method. Once the chain is successfully created, other application - * instances only need to call getChain() to obtain the information about this chain. - * @returns {bool} Whether the chain initialization process was successful. - */ -func (c *chain) InitializeChain() bool { - return false +// CreateChannel calls the an orderer to create a channel on the network +// @param {CreateChannelRequest} request Contains cofiguration information +// @returns {bool} result of the channel creation +func (c *chain) CreateChannel(request CreateChannelRequest) error { + var failureCount int + // Validate request + if request.ConfigData == nil { + return fmt.Errorf("Configuration is required to create a chanel") + } + + signedEnvelope := &common.Envelope{} + err := proto.Unmarshal(request.ConfigData, signedEnvelope) + if err != nil { + return fmt.Errorf("Error unmarshalling channel configuration data: %s", + err.Error()) + } + // Send request + responseMap, err := c.broadcastEnvelope(&SignedEnvelope{ + signature: signedEnvelope.Signature, + Payload: signedEnvelope.Payload, + }) + if err != nil { + return fmt.Errorf("Error broadcasting channel configuration: %s", err.Error()) + } + + for URL, resp := range responseMap { + if resp.Err != nil { + logger.Warningf("Could not broadcast to orderer: %s", URL) + failureCount++ + } + } + // If all orderers returned error, the operation failed + if failureCount == len(responseMap) { + return fmt.Errorf( + "Broadcast failed: Received error from all configured orderers: %s", + responseMap[0].Err) + } + + return nil } // UpdateChain ... diff --git a/fabric-client/chain_test.go b/fabric-client/chain_test.go index 8886842f6e..5873a07932 100644 --- a/fabric-client/chain_test.go +++ b/fabric-client/chain_test.go @@ -21,6 +21,7 @@ package fabricclient import ( "fmt" + "io/ioutil" "testing" mocks "github.com/hyperledger/fabric-sdk-go/fabric-client/mocks" @@ -148,6 +149,32 @@ func TestPrimaryPeer(t *testing.T) { } +func TestCreateChain(t *testing.T) { + client := NewClient() + chain, err := NewChain("testChain", client) + if err != nil { + t.Fatalf(err.Error()) + } + // Create channel without configuration + err = chain.CreateChannel(CreateChannelRequest{}) + if err == nil { + t.Fatalf("Expected error creating channel without config tx") + } + + configTx, err := ioutil.ReadFile("../test/fixtures/channel/testchannel.tx") + if err != nil { + t.Fatalf(err.Error()) + } + // Setup mock orderer + orderer := mockOrderer{fmt.Sprintf("0.0.0.0:1234"), nil} + chain.AddOrderer(&orderer) + // Test with valid cofiguration + err = chain.CreateChannel(CreateChannelRequest{ConfigData: configTx}) + if err != nil { + t.Fatalf("Did not expect error from create channel. Got error: %s", err.Error()) + } +} + func TestConcurrentPeers(t *testing.T) { const numPeers = 10000 chain, err := setupMassiveTestChain(numPeers, 0) diff --git a/fabric-client/orderer_test.go b/fabric-client/orderer_test.go index 207d7a3ab4..115dc3c390 100644 --- a/fabric-client/orderer_test.go +++ b/fabric-client/orderer_test.go @@ -36,7 +36,7 @@ func TestOrdererViaChain(t *testing.T) { if err != nil { t.Fatalf("error from NewChain %v", err) } - orderer, err := CreateNewOrderer("localhost:7050", "", "") + orderer, _ := CreateNewOrderer("localhost:7050", "", "") chain.AddOrderer(orderer) orderers := chain.GetOrderers() diff --git a/test/fixtures/channel/configtx.yaml b/test/fixtures/channel/configtx.yaml index a6c723da5c..7381eec8dc 100644 --- a/test/fixtures/channel/configtx.yaml +++ b/test/fixtures/channel/configtx.yaml @@ -14,7 +14,7 @@ Profiles: <<: *OrdererDefaults Organizations: - *OrdererOrg - Application: + Application: <<: *ApplicationDefaults Organizations: - *Org0 @@ -43,9 +43,9 @@ Organizations: # MSPDir is the filesystem path which contains the MSP configuration ######################################################################### # FIXME: this path needs to be fixed to point to the actual location of # - # the project 'fabric-sdk-node' in the file system # + # the project 'fabric-sdk-go' in the file system # ######################################################################### - MSPDir: /fabric-sdk-node/test/fixtures/channel/crypto-config/ordererOrganizations/ordererOrg1/msp + MSPDir: /fabric-sdk-go/test/fixtures/channel/crypto-config/ordererOrganizations/ordererOrg1/msp # BCCSP (Blockchain crypto provider): Select which crypto implementation or # library to use @@ -54,11 +54,11 @@ Organizations: SW: Hash: SHA2 Security: 256 - # Location of Key Store. If this is unset, a location will + # Location of Key Store. If this is unset, a location will # be chosen using 'MSPDir'/keystore - FileKeyStore: - KeyStore: - + FileKeyStore: + KeyStore: + - &Org0 # DefaultOrg defines the organization which is used in the sampleconfig # of the fabric.git development environment @@ -70,9 +70,9 @@ Organizations: # MSPDir is the filesystem path which contains the MSP configuration ######################################################################### # FIXME: this path needs to be fixed to point to the actual location of # - # the project 'fabric-sdk-node' in the file system # + # the project 'fabric-sdk-go' in the file system # ######################################################################### - MSPDir: /fabric-sdk-node/test/fixtures/channel/crypto-config/peerOrganizations/peerOrg1/msp/ + MSPDir: /fabric-sdk-go/test/fixtures/channel/crypto-config/peerOrganizations/peerOrg1/msp/ # BCCSP (Blockchain crypto provider): Select which crypto implementation or # library to use @@ -81,11 +81,11 @@ Organizations: SW: Hash: SHA2 Security: 256 - # Location of Key Store. If this is unset, a location will + # Location of Key Store. If this is unset, a location will # be chosen using 'MSPDir'/keystore - FileKeyStore: - KeyStore: - + FileKeyStore: + KeyStore: + AnchorPeers: # AnchorPeers defines the location of peers which can be used # for cross org gossip communication. Note, this value is only @@ -106,9 +106,9 @@ Organizations: # MSPDir is the filesystem path which contains the MSP configuration ######################################################################### # FIXME: this path needs to be fixed to point to the actual location of # - # the project 'fabric-sdk-node' in the file system # + # the project 'fabric-sdk-go' in the file system # ######################################################################### - MSPDir: /fabric-sdk-node/test/fixtures/channel/crypto-config/peerOrganizations/peerOrg2/msp/ + MSPDir: /fabric-sdk-go/test/fixtures/channel/crypto-config/peerOrganizations/peerOrg2/msp/ # BCCSP (Blockchain crypto provider): Select which crypto implementation or # library to use @@ -117,11 +117,11 @@ Organizations: SW: Hash: SHA2 Security: 256 - # Location of Key Store. If this is unset, a location will + # Location of Key Store. If this is unset, a location will # be chosen using 'MSPDir'/keystore - FileKeyStore: - KeyStore: - + FileKeyStore: + KeyStore: + AnchorPeers: # AnchorPeers defines the location of peers which can be used # for cross org gossip communication. Note, this value is only @@ -149,7 +149,7 @@ Orderer: &OrdererDefaults - orderer0:7050 # Batch Timeout: The amount of time to wait before creating a batch - BatchTimeout: 10s + BatchTimeout: 1s # Batch Size: Controls the number of messages batched into a block BatchSize: diff --git a/test/fixtures/channel/mychannel.tx b/test/fixtures/channel/testchannel.tx similarity index 95% rename from test/fixtures/channel/mychannel.tx rename to test/fixtures/channel/testchannel.tx index 9384402e3526688e24ff7b020aa1d9a0e0a96e21..75b0b9b353e14a9dd7774cfc4b568fbdb213ed2b 100644 GIT binary patch delta 347 zcmX@>^U#+}4EmtH5lN1|AOWUhstV-M^sl_G98Hss$sX1B>rpcDc$tH$|DW-;L zCWZ!Prsk;zNfySbmS(0VX^ED`$tk9$2B~HSW~oMorlzS$Mg~BomS%>QDJe!4$te~> z3S2D7sYNA167N%s&&`v6^JwNszf`&=uTagNJXuiHQkM(vdZ!2-FSBU{3^VRjc|U%F6m znVXuJrkYwBq$V1h8Yh_~nWh?Bnx&>CCtD_)TO=i#TN;|07#Sv}S|lf$m>3xu7$ylR zaIqw(7L^D|#Cd!P-gtBMC*yAnq2&(0?9PAG5YPJ9uRK|3zc*K}Hy6TIssCO=3zWFn z{fkmki&Be(rfgj1&p%m9AZzj$e$&ZQ1T-e!6>t}q=i+fnEJ@A?$;?g7FD((`7h>gN zHZ++0QAKz1302j}8G`BM0D&!2=ii!;;n5=%;pQjwSd2RUp0 diff --git a/test/fixtures/docker-compose.yaml b/test/fixtures/docker-compose.yaml index 418ecff4ab..7fdfdbb1ec 100644 --- a/test/fixtures/docker-compose.yaml +++ b/test/fixtures/docker-compose.yaml @@ -185,11 +185,3 @@ services: depends_on: - orderer0 - peer2 - - couchdb: - container_name: couchdb - image: couchdb - ports: - - 5984:5984 - environment: - DB_URL: http://localhost:5984/member_db \ No newline at end of file diff --git a/test/integration/chain_queries_test.go b/test/integration/chain_queries_test.go index 2d252fa559..12d42d6f73 100644 --- a/test/integration/chain_queries_test.go +++ b/test/integration/chain_queries_test.go @@ -134,6 +134,6 @@ func TestChainQueries(t *testing.T) { // Test Query Block - retrieve block by non-existent number block, err = chain.QueryBlock(2147483647) if err == nil { - t.Fatalf("QueryBlock return error: %v", err) + t.Fatalf("QueryBlock non-existent didn't return an error") } } diff --git a/test/integration/channel_test.go b/test/integration/channel_test.go new file mode 100644 index 0000000000..cb7e494279 --- /dev/null +++ b/test/integration/channel_test.go @@ -0,0 +1,55 @@ +/* +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 integration + +import ( + "io/ioutil" + "testing" + + "github.com/hyperledger/fabric-sdk-go/config" + "github.com/hyperledger/fabric-sdk-go/fabric-client" +) + +func TestChannelCreation(t *testing.T) { + initializeConfiguration(t) + + testSetup := BaseSetupImpl{} + invokeChain, err := testSetup.GetChain() + if err != nil { + t.Fatal(err) + } + configTx, err := ioutil.ReadFile("../fixtures/channel/testchannel.tx") + if err != nil { + t.Fatalf("Error reading config file: %s", err.Error()) + } + + request := fabricclient.CreateChannelRequest{ConfigData: configTx} + err = invokeChain.CreateChannel(request) + if err != nil { + t.Fatalf(err.Error()) + } +} + +func initializeConfiguration(t *testing.T) { + err := config.InitConfig("../fixtures/config/config_test.yaml") + if err != nil { + t.Fatalf(err.Error()) + } +} diff --git a/test/integration/install_chaincode_test.go b/test/integration/install_chaincode_test.go index c059ea545f..2c2894a8e5 100644 --- a/test/integration/install_chaincode_test.go +++ b/test/integration/install_chaincode_test.go @@ -37,7 +37,7 @@ var chain fabricClient.Chain func TestChaincodeInstallUsingChaincodePath(t *testing.T) { testSetup := BaseSetupImpl{} - chainCodeVersion := "v0" + strconv.Itoa(rand.Intn(100)) + chainCodeVersion := getRandomCCVersion() err := testSetup.InstallCC(chain, "install", chainCodePath, chainCodeVersion, nil, nil) if err != nil { t.Fatalf("installCC return error: %v", err) @@ -59,7 +59,7 @@ func TestChaincodeInstallUsingChaincodePath(t *testing.T) { func TestChaincodeInstallUsingChaincodePackage(t *testing.T) { testSetup := BaseSetupImpl{} - chainCodeVersion := "v0" + strconv.Itoa(rand.Intn(100)) + chainCodeVersion := getRandomCCVersion() testSetup.ChangeGOPATHToDeploy() chaincodePackage, err := fabricClient.PackageCC(chainCodePath, "") if err != nil { @@ -96,6 +96,7 @@ func TestMain(m *testing.M) { os.Exit(code) } -func init() { +func getRandomCCVersion() string { rand.Seed(time.Now().UnixNano()) + return "v0" + strconv.Itoa(rand.Intn(10000000)) }