Skip to content

Commit

Permalink
[FAB-6286] Prevent capabilities until orderer updt
Browse files Browse the repository at this point in the history
All orderers must be upgraded before turning on the channel capabilities
framework for the application.  This CR adds an additional bundle
construction check which ensures that if capabilities are turned on,
that the orderer has agreed to support them already.

Change-Id: If2ed9477aa1f3e4b45b296cb4c92134eb4058551
Signed-off-by: Jason Yellick <[email protected]>
  • Loading branch information
Jason Yellick committed Oct 3, 2017
1 parent 361d609 commit 2827f23
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 17 deletions.
52 changes: 36 additions & 16 deletions common/channelconfig/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ SPDX-License-Identifier: Apache-2.0
package channelconfig

import (
"fmt"

"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/configtx"
configtxapi "github.com/hyperledger/fabric/common/configtx/api"
Expand Down Expand Up @@ -86,11 +84,11 @@ func (b *Bundle) ValidateNew(nb Resources) error {
if oc, ok := b.OrdererConfig(); ok {
noc, ok := nb.OrdererConfig()
if !ok {
return fmt.Errorf("Current config has orderer section, but new config does not")
return errors.New("Current config has orderer section, but new config does not")
}

if oc.ConsensusType() != noc.ConsensusType() {
return fmt.Errorf("Attempted to change consensus type from %s to %s", oc.ConsensusType(), noc.ConsensusType())
return errors.Errorf("Attempted to change consensus type from %s to %s", oc.ConsensusType(), noc.ConsensusType())
}

for orgName, org := range oc.Organizations() {
Expand All @@ -100,15 +98,15 @@ func (b *Bundle) ValidateNew(nb Resources) error {
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return fmt.Errorf("Orderer org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
return errors.Errorf("Orderer org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
}
}
}

if ac, ok := b.ApplicationConfig(); ok {
nac, ok := nb.ApplicationConfig()
if !ok {
return fmt.Errorf("Current config has consortiums section, but new config does not")
return errors.New("Current config has application section, but new config does not")
}

for orgName, org := range ac.Organizations() {
Expand All @@ -118,15 +116,15 @@ func (b *Bundle) ValidateNew(nb Resources) error {
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return fmt.Errorf("Application org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
return errors.Errorf("Application org %s attempted to change MSP ID from %s to %s", orgName, mspID, norg.MSPID())
}
}
}

if cc, ok := b.ConsortiumsConfig(); ok {
ncc, ok := nb.ConsortiumsConfig()
if !ok {
return fmt.Errorf("Current config has consortiums section, but new config does not")
return errors.Errorf("Current config has consortiums section, but new config does not")
}

for consortiumName, consortium := range cc.Consortiums() {
Expand All @@ -142,7 +140,7 @@ func (b *Bundle) ValidateNew(nb Resources) error {
}
mspID := org.MSPID()
if mspID != norg.MSPID() {
return fmt.Errorf("Consortium %s org %s attempted to change MSP ID from %s to %s", consortiumName, orgName, mspID, norg.MSPID())
return errors.Errorf("Consortium %s org %s attempted to change MSP ID from %s to %s", consortiumName, orgName, mspID, norg.MSPID())
}
}
}
Expand Down Expand Up @@ -179,7 +177,7 @@ func NewBundleFromEnvelope(env *cb.Envelope) (*Bundle, error) {
}

if payload.Header == nil {
return nil, fmt.Errorf("envelope header cannot be nil")
return nil, errors.Errorf("envelope header cannot be nil")
}

chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
Expand All @@ -192,12 +190,8 @@ func NewBundleFromEnvelope(env *cb.Envelope) (*Bundle, error) {

// NewBundle creates a new immutable bundle of configuration
func NewBundle(channelID string, config *cb.Config) (*Bundle, error) {
if config == nil {
return nil, fmt.Errorf("config cannot be nil")
}

if config.ChannelGroup == nil {
return nil, fmt.Errorf("config must contain a channel group")
if err := preValidate(config); err != nil {
return nil, err
}

channelConfig, err := NewChannelConfig(config.ChannelGroup)
Expand Down Expand Up @@ -241,3 +235,29 @@ func NewBundle(channelID string, config *cb.Config) (*Bundle, error) {
configtxManager: configtxManager,
}, nil
}

func preValidate(config *cb.Config) error {
if config == nil {
return errors.New("config cannot be nil")
}

if config.ChannelGroup == nil {
return errors.New("config must contain a channel group")
}

if og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok {
if _, ok := og.Values[CapabilitiesKey]; !ok {
if _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok {
return errors.New("cannot enable channel capabilities without orderer support first")
}

if ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok {
if _, ok := ag.Values[CapabilitiesKey]; ok {
return errors.New("cannot enable application capabilities without orderer support first")
}
}
}
}

return nil
}
77 changes: 76 additions & 1 deletion common/channelconfig/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ package channelconfig
import (
"testing"

cb "github.com/hyperledger/fabric/protos/common"
ab "github.com/hyperledger/fabric/protos/orderer"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -44,7 +45,7 @@ func TestValidateNew(t *testing.T) {

err := cb.ValidateNew(nb)
assert.Error(t, err)
assert.Regexp(t, "Current config has consortiums section, but new config does not", err.Error())
assert.Regexp(t, "Current config has application section, but new config does not", err.Error())
})

t.Run("DisappearingConsortiumsConfig", func(t *testing.T) {
Expand Down Expand Up @@ -200,3 +201,77 @@ func TestValidateNew(t *testing.T) {
assert.Regexp(t, "Consortium consortium1 org org3 attempted to change MSP ID from", err.Error())
})
}

func TestPrevalidation(t *testing.T) {
t.Run("NilConfig", func(t *testing.T) {
err := preValidate(nil)

assert.Error(t, err)
assert.Regexp(t, "config cannot be nil", err.Error())
})

t.Run("NilChannelGroup", func(t *testing.T) {
err := preValidate(&cb.Config{})

assert.Error(t, err)
assert.Regexp(t, "config must contain a channel group", err.Error())
})

t.Run("BadChannelCapabilities", func(t *testing.T) {
err := preValidate(&cb.Config{
ChannelGroup: &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
OrdererGroupKey: &cb.ConfigGroup{},
},
Values: map[string]*cb.ConfigValue{
CapabilitiesKey: &cb.ConfigValue{},
},
},
})

assert.Error(t, err)
assert.Regexp(t, "cannot enable channel capabilities without orderer support first", err.Error())
})

t.Run("BadApplicationCapabilities", func(t *testing.T) {
err := preValidate(&cb.Config{
ChannelGroup: &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
ApplicationGroupKey: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
CapabilitiesKey: &cb.ConfigValue{},
},
},
OrdererGroupKey: &cb.ConfigGroup{},
},
},
})

assert.Error(t, err)
assert.Regexp(t, "cannot enable application capabilities without orderer support first", err.Error())
})

t.Run("ValidCapabilities", func(t *testing.T) {
err := preValidate(&cb.Config{
ChannelGroup: &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
ApplicationGroupKey: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
CapabilitiesKey: &cb.ConfigValue{},
},
},
OrdererGroupKey: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
CapabilitiesKey: &cb.ConfigValue{},
},
},
},
Values: map[string]*cb.ConfigValue{
CapabilitiesKey: &cb.ConfigValue{},
},
},
})

assert.NoError(t, err)
})
}

0 comments on commit 2827f23

Please sign in to comment.