diff --git a/common/configtx/api/api.go b/common/configtx/api/api.go index 31e1f2e1620..4d89d0e1407 100644 --- a/common/configtx/api/api.go +++ b/common/configtx/api/api.go @@ -40,12 +40,18 @@ type ChannelConfig interface { OrdererAddresses() []string } -// ApplicationConfig stores the common shared application config -type ApplicationConfig interface { +// ApplicationOrgConfig stores the per org application config +type ApplicationOrgConfig interface { // AnchorPeers returns the list of gossip anchor peers AnchorPeers() []*pb.AnchorPeer } +// ApplicationConfig stores the common shared application config +type ApplicationConfig interface { + // Organizations returns a map of org ID to ApplicationOrgConfig + Organizations() map[string]ApplicationOrgConfig +} + // OrdererConfig stores the common shared orderer config type OrdererConfig interface { // ConsensusType returns the configured consensus type diff --git a/common/configtx/handlers/application/organization.go b/common/configtx/handlers/application/organization.go new file mode 100644 index 00000000000..0ee97291287 --- /dev/null +++ b/common/configtx/handlers/application/organization.go @@ -0,0 +1,106 @@ +/* +Copyright IBM Corp. 2017 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 application + +import ( + "fmt" + + "github.com/hyperledger/fabric/common/configtx/handlers" + mspconfig "github.com/hyperledger/fabric/common/configtx/handlers/msp" + cb "github.com/hyperledger/fabric/protos/common" + pb "github.com/hyperledger/fabric/protos/peer" + + "github.com/golang/protobuf/proto" + logging "github.com/op/go-logging" +) + +// Application org config keys +const ( + // AnchorPeersKey is the key name for the AnchorPeers ConfigValue + AnchorPeersKey = "AnchorPeers" +) + +type applicationOrgConfig struct { + anchorPeers []*pb.AnchorPeer +} + +// SharedConfigImpl is an implementation of Manager and configtx.ConfigHandler +// In general, it should only be referenced as an Impl for the configtx.Manager +type ApplicationOrgConfig struct { + *handlers.OrgConfig + pendingConfig *applicationOrgConfig + config *applicationOrgConfig + + mspConfig *mspconfig.MSPConfigHandler +} + +// NewSharedConfigImpl creates a new SharedConfigImpl with the given CryptoHelper +func NewApplicationOrgConfig(id string, mspConfig *mspconfig.MSPConfigHandler) *ApplicationOrgConfig { + return &ApplicationOrgConfig{ + OrgConfig: handlers.NewOrgConfig(id, mspConfig), + config: &applicationOrgConfig{}, + } +} + +// AnchorPeers returns the list of valid orderer addresses to connect to to invoke Broadcast/Deliver +func (oc *ApplicationOrgConfig) AnchorPeers() []*pb.AnchorPeer { + return oc.config.anchorPeers +} + +// BeginConfig is used to start a new config proposal +func (oc *ApplicationOrgConfig) BeginConfig() { + logger.Debugf("Beginning a possible new org config") + if oc.pendingConfig != nil { + logger.Panicf("Programming error, cannot call begin in the middle of a proposal") + } + oc.pendingConfig = &applicationOrgConfig{} +} + +// RollbackConfig is used to abandon a new config proposal +func (oc *ApplicationOrgConfig) RollbackConfig() { + logger.Debugf("Rolling back proposed org config") + oc.pendingConfig = nil +} + +// CommitConfig is used to commit a new config proposal +func (oc *ApplicationOrgConfig) CommitConfig() { + logger.Debugf("Committing new org config") + if oc.pendingConfig == nil { + logger.Panicf("Programming error, cannot call commit without an existing proposal") + } + oc.config = oc.pendingConfig + oc.pendingConfig = nil +} + +// ProposeConfig is used to add new config to the config proposal +func (oc *ApplicationOrgConfig) ProposeConfig(key string, configValue *cb.ConfigValue) error { + switch key { + case AnchorPeersKey: + anchorPeers := &pb.AnchorPeers{} + if err := proto.Unmarshal(configValue.Value, anchorPeers); err != nil { + return fmt.Errorf("Unmarshaling error for %s: %s", key, err) + } + if logger.IsEnabledFor(logging.DEBUG) { + logger.Debugf("Setting %s to %v", key, anchorPeers.AnchorPeers) + } + oc.pendingConfig.anchorPeers = anchorPeers.AnchorPeers + default: + return oc.OrgConfig.ProposeConfig(key, configValue) + } + + return nil +} diff --git a/common/configtx/handlers/application/organization_test.go b/common/configtx/handlers/application/organization_test.go new file mode 100644 index 00000000000..51429916bd1 --- /dev/null +++ b/common/configtx/handlers/application/organization_test.go @@ -0,0 +1,86 @@ +/* +Copyright IBM Corp. 2017 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 application + +import ( + "testing" + + configtxapi "github.com/hyperledger/fabric/common/configtx/api" + cb "github.com/hyperledger/fabric/protos/common" + pb "github.com/hyperledger/fabric/protos/peer" + + logging "github.com/op/go-logging" + "github.com/stretchr/testify/assert" +) + +func init() { + logging.SetLevel(logging.DEBUG, "") +} + +func makeInvalidConfigValue() *cb.ConfigValue { + return &cb.ConfigValue{ + Value: []byte("Garbage Data"), + } +} + +func groupToKeyValue(configGroup *cb.ConfigGroup) (string, *cb.ConfigValue) { + for _, group := range configGroup.Groups[GroupKey].Groups { + for key, value := range group.Values { + return key, value + } + } + panic("No value encoded") +} + +func TestApplicationOrgInterface(t *testing.T) { + _ = configtxapi.SubInitializer(NewApplicationOrgConfig("id", nil)) +} + +func TestApplicationOrgDoubleBegin(t *testing.T) { + m := NewApplicationOrgConfig("id", nil) + m.BeginConfig() + assert.Panics(t, m.BeginConfig, "Two begins back to back should have caused a panic") +} + +func TestApplicationOrgCommitWithoutBegin(t *testing.T) { + m := NewApplicationOrgConfig("id", nil) + assert.Panics(t, m.CommitConfig, "Committing without beginning should have caused a panic") +} + +func TestApplicationOrgRollback(t *testing.T) { + m := NewApplicationOrgConfig("id", nil) + m.pendingConfig = &applicationOrgConfig{} + m.RollbackConfig() + assert.Nil(t, m.pendingConfig, "Should have cleared pending config on rollback") +} + +func TestApplicationOrgAnchorPeers(t *testing.T) { + endVal := []*pb.AnchorPeer{ + &pb.AnchorPeer{Host: "foo", Port: 234, Cert: []byte("foocert")}, + &pb.AnchorPeer{Host: "bar", Port: 237, Cert: []byte("barcert")}, + } + invalidMessage := makeInvalidConfigValue() + validMessage := TemplateAnchorPeers("id", endVal) + m := NewApplicationOrgConfig("id", nil) + m.BeginConfig() + + assert.Error(t, m.ProposeConfig(AnchorPeersKey, invalidMessage), "Should have failed on invalid message") + assert.NoError(t, m.ProposeConfig(groupToKeyValue(validMessage)), "Should not have failed on invalid message") + m.CommitConfig() + + assert.Equal(t, m.AnchorPeers(), endVal, "Did not set updated anchor peers") +} diff --git a/common/configtx/handlers/application/sharedconfig.go b/common/configtx/handlers/application/sharedconfig.go index 797649e88a3..c8dda514df9 100644 --- a/common/configtx/handlers/application/sharedconfig.go +++ b/common/configtx/handlers/application/sharedconfig.go @@ -23,9 +23,7 @@ import ( "github.com/hyperledger/fabric/common/configtx/handlers" "github.com/hyperledger/fabric/common/configtx/handlers/msp" cb "github.com/hyperledger/fabric/protos/common" - pb "github.com/hyperledger/fabric/protos/peer" - "github.com/golang/protobuf/proto" "github.com/op/go-logging" ) @@ -37,7 +35,8 @@ const ( var orgSchema = &cb.ConfigGroupSchema{ Groups: map[string]*cb.ConfigGroupSchema{}, Values: map[string]*cb.ConfigValueSchema{ - "MSP": nil, // TODO, consolidate into a constant once common org code exists + AnchorPeersKey: nil, + handlers.MSPKey: nil, // TODO, consolidate into a constant once common org code exists }, Policies: map[string]*cb.ConfigPolicySchema{ // TODO, set appropriately once hierarchical policies are implemented @@ -48,25 +47,16 @@ var Schema = &cb.ConfigGroupSchema{ Groups: map[string]*cb.ConfigGroupSchema{ "": orgSchema, }, - Values: map[string]*cb.ConfigValueSchema{ - AnchorPeersKey: nil, - }, + Values: map[string]*cb.ConfigValueSchema{}, Policies: map[string]*cb.ConfigPolicySchema{ // TODO, set appropriately once hierarchical policies are implemented }, } -// Peer config keys -const ( - // AnchorPeersKey is the key name for the AnchorPeers ConfigValue - AnchorPeersKey = "AnchorPeers" -) - -var logger = logging.MustGetLogger("peer/sharedconfig") +var logger = logging.MustGetLogger("common/configtx/handlers/application") type sharedConfig struct { - anchorPeers []*pb.AnchorPeer - orgs map[string]*handlers.OrgConfig + orgs map[string]api.ApplicationOrgConfig } // SharedConfigImpl is an implementation of Manager and configtx.ConfigHandler @@ -86,11 +76,6 @@ func NewSharedConfigImpl(mspConfig *msp.MSPConfigHandler) *SharedConfigImpl { } } -// AnchorPeers returns the list of valid orderer addresses to connect to to invoke Broadcast/Deliver -func (di *SharedConfigImpl) AnchorPeers() []*pb.AnchorPeer { - return di.config.anchorPeers -} - // BeginConfig is used to start a new config proposal func (di *SharedConfigImpl) BeginConfig() { logger.Debugf("Beginning a possible new peer shared config") @@ -98,7 +83,7 @@ func (di *SharedConfigImpl) BeginConfig() { logger.Panicf("Programming error, cannot call begin in the middle of a proposal") } di.pendingConfig = &sharedConfig{ - orgs: make(map[string]*handlers.OrgConfig), + orgs: make(map[string]api.ApplicationOrgConfig), } } @@ -120,22 +105,15 @@ func (di *SharedConfigImpl) CommitConfig() { // ProposeConfig is used to add new config to the config proposal func (di *SharedConfigImpl) ProposeConfig(key string, configValue *cb.ConfigValue) error { - switch key { - case AnchorPeersKey: - anchorPeers := &pb.AnchorPeers{} - if err := proto.Unmarshal(configValue.Value, anchorPeers); err != nil { - return fmt.Errorf("Unmarshaling error for %s: %s", key, err) - } - if logger.IsEnabledFor(logging.DEBUG) { - logger.Debugf("Setting %s to %v", key, anchorPeers.AnchorPeers) - } - di.pendingConfig.anchorPeers = anchorPeers.AnchorPeers - default: - logger.Warningf("Uknown Peer config item with key %s", key) - } + logger.Warningf("Uknown Peer config item with key %s", key) return nil } +// Organizations returns a map of org ID to ApplicationOrgConfig +func (di *SharedConfigImpl) Organizations() map[string]api.ApplicationOrgConfig { + return di.config.orgs +} + // Handler returns the associated api.Handler for the given path func (pm *SharedConfigImpl) Handler(path []string) (api.Handler, error) { if len(path) == 0 { @@ -148,8 +126,8 @@ func (pm *SharedConfigImpl) Handler(path []string) (api.Handler, error) { org, ok := pm.pendingConfig.orgs[path[0]] if !ok { - org = handlers.NewOrgConfig(path[0], pm.mspConfig) + org = NewApplicationOrgConfig(path[0], pm.mspConfig) pm.pendingConfig.orgs[path[0]] = org } - return org, nil + return org.(*ApplicationOrgConfig), nil } diff --git a/common/configtx/handlers/application/sharedconfig_test.go b/common/configtx/handlers/application/sharedconfig_test.go index 3ba2b2a2724..8938812110e 100644 --- a/common/configtx/handlers/application/sharedconfig_test.go +++ b/common/configtx/handlers/application/sharedconfig_test.go @@ -17,12 +17,9 @@ limitations under the License. package application import ( - "reflect" "testing" configtxapi "github.com/hyperledger/fabric/common/configtx/api" - cb "github.com/hyperledger/fabric/protos/common" - pb "github.com/hyperledger/fabric/protos/peer" logging "github.com/op/go-logging" ) @@ -31,24 +28,11 @@ func init() { logging.SetLevel(logging.DEBUG, "") } -func makeInvalidConfigValue() *cb.ConfigValue { - return &cb.ConfigValue{ - Value: []byte("Garbage Data"), - } -} - -func groupToKeyValue(configGroup *cb.ConfigGroup) (string, *cb.ConfigValue) { - for key, value := range configGroup.Groups[GroupKey].Values { - return key, value - } - panic("No value encoded") -} - -func TestInterface(t *testing.T) { +func TestApplicationInterface(t *testing.T) { _ = configtxapi.ApplicationConfig(NewSharedConfigImpl(nil)) } -func TestDoubleBegin(t *testing.T) { +func TestApplicationDoubleBegin(t *testing.T) { defer func() { if err := recover(); err == nil { t.Fatalf("Should have panicked on multiple begin configs") @@ -60,7 +44,7 @@ func TestDoubleBegin(t *testing.T) { m.BeginConfig() } -func TestCommitWithoutBegin(t *testing.T) { +func TestApplicationCommitWithoutBegin(t *testing.T) { defer func() { if err := recover(); err == nil { t.Fatalf("Should have panicked on multiple begin configs") @@ -71,7 +55,7 @@ func TestCommitWithoutBegin(t *testing.T) { m.CommitConfig() } -func TestRollback(t *testing.T) { +func TestApplicationRollback(t *testing.T) { m := NewSharedConfigImpl(nil) m.pendingConfig = &sharedConfig{} m.RollbackConfig() @@ -79,30 +63,3 @@ func TestRollback(t *testing.T) { t.Fatalf("Should have cleared pending config on rollback") } } - -func TestAnchorPeers(t *testing.T) { - endVal := []*pb.AnchorPeer{ - &pb.AnchorPeer{Host: "foo", Port: 234, Cert: []byte("foocert")}, - &pb.AnchorPeer{Host: "bar", Port: 237, Cert: []byte("barcert")}, - } - invalidMessage := makeInvalidConfigValue() - validMessage := TemplateAnchorPeers(endVal) - m := NewSharedConfigImpl(nil) - m.BeginConfig() - - err := m.ProposeConfig(AnchorPeersKey, invalidMessage) - if err == nil { - t.Fatalf("Should have failed on invalid message") - } - - err = m.ProposeConfig(groupToKeyValue(validMessage)) - if err != nil { - t.Fatalf("Error applying valid config: %s", err) - } - - m.CommitConfig() - - if newVal := m.AnchorPeers(); !reflect.DeepEqual(newVal, endVal) { - t.Fatalf("Unexpected anchor peers, got %v expected %v", newVal, endVal) - } -} diff --git a/common/configtx/handlers/application/sharedconfig_util.go b/common/configtx/handlers/application/sharedconfig_util.go index ba2f7d38d2c..ea4689a78dd 100644 --- a/common/configtx/handlers/application/sharedconfig_util.go +++ b/common/configtx/handlers/application/sharedconfig_util.go @@ -22,23 +22,17 @@ import ( "github.com/hyperledger/fabric/protos/utils" ) -var defaultAnchorPeers = []*pb.AnchorPeer{} - -func configGroup(key string, value []byte) *cb.ConfigGroup { +func configGroup(orgID string, key string, value []byte) *cb.ConfigGroup { result := cb.NewConfigGroup() result.Groups[GroupKey] = cb.NewConfigGroup() - result.Groups[GroupKey].Values[key] = &cb.ConfigValue{ + result.Groups[GroupKey].Groups[orgID] = cb.NewConfigGroup() + result.Groups[GroupKey].Groups[orgID].Values[key] = &cb.ConfigValue{ Value: value, } return result } // TemplateAnchorPeers creates a headerless config item representing the anchor peers -func TemplateAnchorPeers(anchorPeers []*pb.AnchorPeer) *cb.ConfigGroup { - return configGroup(AnchorPeersKey, utils.MarshalOrPanic(&pb.AnchorPeers{AnchorPeers: anchorPeers})) -} - -// DefaultAnchorPeers creates a headerless config item for the default orderer addresses -func DefaultAnchorPeers() *cb.ConfigGroup { - return TemplateAnchorPeers(defaultAnchorPeers) +func TemplateAnchorPeers(orgID string, anchorPeers []*pb.AnchorPeer) *cb.ConfigGroup { + return configGroup(orgID, AnchorPeersKey, utils.MarshalOrPanic(&pb.AnchorPeers{AnchorPeers: anchorPeers})) } diff --git a/common/configtx/test/helper.go b/common/configtx/test/helper.go index e64b9a2bd1f..ad4a2207156 100644 --- a/common/configtx/test/helper.go +++ b/common/configtx/test/helper.go @@ -85,23 +85,27 @@ func OrdererTemplate() configtx.Template { return provisional.New(genConf).ChannelTemplate() } -// MSPTemplate returns the test MSP template -func MSPTemplate() configtx.Template { - const sampleID = "SAMPLE" - mspConf, err := msp.GetLocalMspConfig(sampleMSPPath, sampleID) +const sampleOrgID = "SAMPLE" + +// ApplicationOrgTemplate returns the SAMPLE org with MSP template +func ApplicationOrgTemplate() configtx.Template { + mspConf, err := msp.GetLocalMspConfig(sampleMSPPath, sampleOrgID) if err != nil { logger.Panicf("Could not load sample MSP config: %s", err) } - return configtx.NewSimpleTemplate(configtxmsp.TemplateGroupMSP([]string{configtxapplication.GroupKey, sampleID}, mspConf), - configtxmsp.TemplateGroupMSP([]string{configtxorderer.GroupKey, sampleID}, mspConf)) + return configtx.NewSimpleTemplate(configtxmsp.TemplateGroupMSP([]string{configtxapplication.GroupKey, sampleOrgID}, mspConf)) } -// ApplicationTemplate returns the test application template -func ApplicationTemplate() configtx.Template { - return configtx.NewSimpleTemplate(configtxapplication.DefaultAnchorPeers()) +// OrdererOrgTemplate returns the SAMPLE org with MSP template +func OrdererOrgTemplate() configtx.Template { + mspConf, err := msp.GetLocalMspConfig(sampleMSPPath, sampleOrgID) + if err != nil { + logger.Panicf("Could not load sample MSP config: %s", err) + } + return configtx.NewSimpleTemplate(configtxmsp.TemplateGroupMSP([]string{configtxorderer.GroupKey, sampleOrgID}, mspConf)) } // CompositeTemplate returns the composite template of peer, orderer, and MSP func CompositeTemplate() configtx.Template { - return configtx.NewCompositeTemplate(MSPTemplate(), OrdererTemplate(), ApplicationTemplate()) + return configtx.NewCompositeTemplate(OrdererTemplate(), ApplicationOrgTemplate(), OrdererOrgTemplate()) } diff --git a/common/configtx/test/helper_test.go b/common/configtx/test/helper_test.go index 259dc22e9b8..f85cd5a17d4 100644 --- a/common/configtx/test/helper_test.go +++ b/common/configtx/test/helper_test.go @@ -37,12 +37,12 @@ func TestOrdererTemplate(t *testing.T) { _ = OrdererTemplate() } -func TestMSPTemplate(t *testing.T) { - _ = MSPTemplate() +func TestOrdererOrgTemplate(t *testing.T) { + _ = OrdererOrgTemplate() } -func TestApplicationTemplate(t *testing.T) { - _ = ApplicationTemplate() +func TestApplicationOrgTemplate(t *testing.T) { + _ = ApplicationOrgTemplate() } func TestCompositeTemplate(t *testing.T) { diff --git a/gossip/service/eventer.go b/gossip/service/eventer.go index ecc5d0d03f6..ee80deb0376 100644 --- a/gossip/service/eventer.go +++ b/gossip/service/eventer.go @@ -19,6 +19,8 @@ package service import ( "reflect" + configtxapi "github.com/hyperledger/fabric/common/configtx/api" + "github.com/hyperledger/fabric/protos/peer" ) @@ -27,8 +29,8 @@ type Config interface { // ChainID returns the chainID for this channel ChainID() string - // AnchorPeers should return the current list of anchor peers - AnchorPeers() []*peer.AnchorPeer + // Organizations returns a map of org ID to ApplicationOrgConfig + Organizations() map[string]configtxapi.ApplicationOrgConfig // Sequence should return the sequence number of the current configuration Sequence() uint64 @@ -42,6 +44,7 @@ type ConfigProcessor interface { type configStore struct { anchorPeers []*peer.AnchorPeer + orgMap map[string]configtxapi.ApplicationOrgConfig } type configEventReceiver interface { @@ -64,27 +67,24 @@ func newConfigEventer(receiver configEventReceiver) *configEventer { // but only if the configuration value actually changed // Note, that a changing sequence number is ignored as changing configuration func (ce *configEventer) ProcessConfigUpdate(config Config) { - logger.Debugf("Processing new config for chain %s", config.ChainID()) - - changed := false - - newAnchorPeers := config.AnchorPeers() + logger.Debugf("Processing new config for channel %s", config.ChainID()) - if ce.lastConfig != nil { - if !reflect.DeepEqual(newAnchorPeers, ce.lastConfig.anchorPeers) { - changed = true - } - } else { - changed = true + if ce.lastConfig != nil && reflect.DeepEqual(ce.lastConfig.orgMap, config.Organizations()) { + logger.Debugf("Ignoring new config for channel %s because it contained no anchor peer updates", config.ChainID()) + return } - if changed { - newConfig := &configStore{ - anchorPeers: config.AnchorPeers(), - } - ce.lastConfig = newConfig + var newAnchorPeers []*peer.AnchorPeer + for _, group := range config.Organizations() { + newAnchorPeers = append(newAnchorPeers, group.AnchorPeers()...) + } - logger.Debugf("Calling out because config was updated for chain %s", config.ChainID()) - ce.receiver.configUpdated(config) + newConfig := &configStore{ + orgMap: config.Organizations(), + anchorPeers: newAnchorPeers, } + ce.lastConfig = newConfig + + logger.Debugf("Calling out because config was updated for channel %s", config.ChainID()) + ce.receiver.configUpdated(config) } diff --git a/gossip/service/eventer_test.go b/gossip/service/eventer_test.go index 19bd3f8e6c6..9300aa9465b 100644 --- a/gossip/service/eventer_test.go +++ b/gossip/service/eventer_test.go @@ -20,19 +20,26 @@ import ( "reflect" "testing" + configtxapi "github.com/hyperledger/fabric/common/configtx/api" "github.com/hyperledger/fabric/protos/peer" ) const testChainID = "foo" +type applicationOrgs []*peer.AnchorPeer + +func (ao applicationOrgs) AnchorPeers() []*peer.AnchorPeer { + return ao +} + type mockReceiver struct { - anchorPeers []*peer.AnchorPeer - sequence uint64 + orgs map[string]configtxapi.ApplicationOrgConfig + sequence uint64 } func (mr *mockReceiver) configUpdated(config Config) { - logger.Debugf("[TEST] Setting config to %d %v", config.Sequence(), config.AnchorPeers()) - mr.anchorPeers = config.AnchorPeers() + logger.Debugf("[TEST] Setting config to %d %v", config.Sequence(), config.Organizations()) + mr.orgs = config.Organizations() mr.sequence = config.Sequence() } @@ -42,21 +49,25 @@ func (mc *mockConfig) Sequence() uint64 { return mc.sequence } -func (mc *mockConfig) AnchorPeers() []*peer.AnchorPeer { - return mc.anchorPeers +func (mc *mockConfig) Organizations() map[string]configtxapi.ApplicationOrgConfig { + return mc.orgs } func (mc *mockConfig) ChainID() string { return testChainID } +const testOrgID = "testID" + func TestInitialUpdate(t *testing.T) { mc := &mockConfig{ sequence: 7, - anchorPeers: []*peer.AnchorPeer{ - &peer.AnchorPeer{ - Port: 9, - }, + orgs: map[string]configtxapi.ApplicationOrgConfig{ + testOrgID: applicationOrgs([]*peer.AnchorPeer{ + &peer.AnchorPeer{ + Port: 9, + }, + }), }, } @@ -73,10 +84,12 @@ func TestInitialUpdate(t *testing.T) { func TestSecondUpdate(t *testing.T) { mc := &mockConfig{ sequence: 7, - anchorPeers: []*peer.AnchorPeer{ - &peer.AnchorPeer{ - Port: 9, - }, + orgs: map[string]configtxapi.ApplicationOrgConfig{ + testOrgID: applicationOrgs([]*peer.AnchorPeer{ + &peer.AnchorPeer{ + Port: 9, + }, + }), }, } @@ -86,10 +99,12 @@ func TestSecondUpdate(t *testing.T) { ce.ProcessConfigUpdate(mc) mc.sequence = 8 - mc.anchorPeers = []*peer.AnchorPeer{ - &peer.AnchorPeer{ - Port: 10, - }, + mc.orgs = map[string]configtxapi.ApplicationOrgConfig{ + testOrgID: applicationOrgs([]*peer.AnchorPeer{ + &peer.AnchorPeer{ + Port: 10, + }, + }), } ce.ProcessConfigUpdate(mc) @@ -102,10 +117,12 @@ func TestSecondUpdate(t *testing.T) { func TestSecondSameUpdate(t *testing.T) { mc := &mockConfig{ sequence: 7, - anchorPeers: []*peer.AnchorPeer{ - &peer.AnchorPeer{ - Port: 9, - }, + orgs: map[string]configtxapi.ApplicationOrgConfig{ + testOrgID: applicationOrgs([]*peer.AnchorPeer{ + &peer.AnchorPeer{ + Port: 9, + }, + }), }, } @@ -114,14 +131,14 @@ func TestSecondSameUpdate(t *testing.T) { ce := newConfigEventer(mr) ce.ProcessConfigUpdate(mc) mr.sequence = 0 - mr.anchorPeers = nil + mr.orgs = nil ce.ProcessConfigUpdate(mc) if mr.sequence != 0 { t.Errorf("Should not have updated sequence when reprocessing same config") } - if mr.anchorPeers != nil { + if mr.orgs != nil { t.Errorf("Should not have updated anchor peers when reprocessing same config") } } @@ -129,10 +146,12 @@ func TestSecondSameUpdate(t *testing.T) { func TestUpdatedSeqOnly(t *testing.T) { mc := &mockConfig{ sequence: 7, - anchorPeers: []*peer.AnchorPeer{ - &peer.AnchorPeer{ - Port: 9, - }, + orgs: map[string]configtxapi.ApplicationOrgConfig{ + testOrgID: applicationOrgs([]*peer.AnchorPeer{ + &peer.AnchorPeer{ + Port: 9, + }, + }), }, } @@ -147,7 +166,7 @@ func TestUpdatedSeqOnly(t *testing.T) { t.Errorf("Should not have updated sequence when reprocessing same config") } - if !reflect.DeepEqual(mr.anchorPeers, mc.anchorPeers) { + if !reflect.DeepEqual(mr.orgs, mc.orgs) { t.Errorf("Should not have cleared anchor peers when reprocessing newer config with higher sequence") } } diff --git a/gossip/service/gossip_service.go b/gossip/service/gossip_service.go index 6523e6a78b2..2dd24763a3c 100644 --- a/gossip/service/gossip_service.go +++ b/gossip/service/gossip_service.go @@ -179,13 +179,15 @@ func (g *gossipServiceImpl) InitializeChannel(chainID string, committer committe // configUpdated constructs a joinChannelMessage and sends it to the gossipSvc func (g *gossipServiceImpl) configUpdated(config Config) { jcm := &joinChannelMessage{seqNum: config.Sequence(), anchorPeers: []api.AnchorPeer{}} - for _, ap := range config.AnchorPeers() { - anchorPeer := api.AnchorPeer{ - Host: ap.Host, - Port: int(ap.Port), - Cert: api.PeerIdentityType(ap.Cert), + for _, org := range config.Organizations() { + for _, ap := range org.AnchorPeers() { + anchorPeer := api.AnchorPeer{ + Host: ap.Host, + Port: int(ap.Port), + Cert: api.PeerIdentityType(ap.Cert), + } + jcm.anchorPeers = append(jcm.anchorPeers, anchorPeer) } - jcm.anchorPeers = append(jcm.anchorPeers, anchorPeer) } // Initialize new state provider for given committer diff --git a/peer/channel/create.go b/peer/channel/create.go index 92eb3033efa..91210874a64 100644 --- a/peer/channel/create.go +++ b/peer/channel/create.go @@ -54,9 +54,10 @@ func sendCreateChainTransaction(cf *ChannelCmdFactory) error { } //TODO this is a temporary hack until `orderer.template` and 'msp.template' is supplied from the CLI oTemplate := configtxtest.OrdererTemplate() - mspTemplate := configtxtest.MSPTemplate() - gossTemplate := configtx.NewSimpleTemplate(configtxapplication.TemplateAnchorPeers(anchorPeers)) - chCrtTemp := configtx.NewCompositeTemplate(oTemplate, mspTemplate, gossTemplate) + oOrgTemplate := configtxtest.OrdererOrgTemplate() + appOrgTemplate := configtxtest.ApplicationOrgTemplate() + gossTemplate := configtx.NewSimpleTemplate(configtxapplication.TemplateAnchorPeers("XXXFakeOrg", anchorPeers)) + chCrtTemp := configtx.NewCompositeTemplate(oTemplate, oOrgTemplate, appOrgTemplate, gossTemplate) signer, err := mspmgmt.GetLocalMSP().GetDefaultSigningIdentity() if err != nil { diff --git a/peer/node/start.go b/peer/node/start.go index bc355bbd4f4..b2319f8cbcb 100644 --- a/peer/node/start.go +++ b/peer/node/start.go @@ -27,7 +27,6 @@ import ( "syscall" "time" - "github.com/hyperledger/fabric/common/configtx" "github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/common/genesis" "github.com/hyperledger/fabric/common/util" @@ -162,7 +161,7 @@ func serve(args []string) error { // We create a genesis block for the test // chain with its MSP so that we can transact - block, err := genesis.NewFactoryImpl(configtx.NewCompositeTemplate(test.MSPTemplate())).Block(chainID) + block, err := genesis.NewFactoryImpl(test.ApplicationOrgTemplate()).Block(chainID) if nil != err { panic(fmt.Sprintf("Unable to create genesis block for [%s] due to [%s]", chainID, err)) }