Unverified Commit 59188f1a authored by Jason Yellick's avatar Jason Yellick Committed by Artem Barger
Browse files

FAB-14040 Explicitly gen default config template



The configtxgen tool currently assumes that the current profile is the
source of the config template it uses to compute the channel creation
request.  This CR makes this explicit and allows a non-default template
to be passed in (to be implemented in a future CR).

Change-Id: Ia3c32e8fc4061df9556a17534dc9233e94c00d0f
Signed-off-by: default avatarJason Yellick <jyellick@us.ibm.com>
parent 407c8fa1
......@@ -7,7 +7,6 @@ SPDX-License-Identifier: Apache-2.0
package encoder
import (
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/cauthdsl"
"github.com/hyperledger/fabric/common/channelconfig"
"github.com/hyperledger/fabric/common/crypto"
......@@ -128,10 +127,6 @@ func addSignaturePolicyDefaults(cg *cb.ConfigGroup, mspID string, devMode bool)
// configuration. All mod_policy values are set to "Admins" for this group, with the exception of the OrdererAddresses
// value which is set to "/Channel/Orderer/Admins".
func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
if conf.Orderer == nil {
return nil, errors.New("missing orderer config section")
}
channelGroup := cb.NewConfigGroup()
if len(conf.Policies) == 0 {
logger.Warningf("Default policy emission is deprecated, please include policy specifications for the channel group in configtx.yaml")
......@@ -144,7 +139,11 @@ func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
addValue(channelGroup, channelconfig.HashingAlgorithmValue(), channelconfig.AdminsPolicyKey)
addValue(channelGroup, channelconfig.BlockDataHashingStructureValue(), channelconfig.AdminsPolicyKey)
addValue(channelGroup, channelconfig.OrdererAddressesValue(conf.Orderer.Addresses), ordererAdminsPolicyName)
ordererAddresses := []string{}
if conf.Orderer != nil {
ordererAddresses = conf.Orderer.Addresses
}
addValue(channelGroup, channelconfig.OrdererAddressesValue(ordererAddresses), ordererAdminsPolicyName)
if conf.Consortium != "" {
addValue(channelGroup, channelconfig.ConsortiumValue(conf.Consortium), channelconfig.AdminsPolicyKey)
......@@ -155,9 +154,11 @@ func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
}
var err error
channelGroup.Groups[channelconfig.OrdererGroupKey], err = NewOrdererGroup(conf.Orderer)
if err != nil {
return nil, errors.Wrap(err, "could not create orderer group")
if conf.Orderer != nil {
channelGroup.Groups[channelconfig.OrdererGroupKey], err = NewOrdererGroup(conf.Orderer)
if err != nil {
return nil, errors.Wrap(err, "could not create orderer group")
}
}
if conf.Application != nil {
......@@ -368,7 +369,7 @@ func NewConsortiumGroup(conf *genesisconfig.Consortium) (*cb.ConfigGroup, error)
// NewChannelCreateConfigUpdate generates a ConfigUpdate which can be sent to the orderer to create a new channel. Optionally, the channel group of the
// ordering system channel may be passed in, and the resulting ConfigUpdate will extract the appropriate versions from this file.
func NewChannelCreateConfigUpdate(channelID string, conf *genesisconfig.Profile) (*cb.ConfigUpdate, error) {
func NewChannelCreateConfigUpdate(channelID string, conf *genesisconfig.Profile, templateConfig *cb.ConfigGroup) (*cb.ConfigUpdate, error) {
if conf.Application == nil {
return nil, errors.New("cannot define a new channel with no Application section")
}
......@@ -377,26 +378,12 @@ func NewChannelCreateConfigUpdate(channelID string, conf *genesisconfig.Profile)
return nil, errors.New("cannot define a new channel with no Consortium value")
}
// Parse only the application section, and encapsulate it inside a channel group
ag, err := NewApplicationGroup(conf.Application)
newChannelGroup, err := NewChannelGroup(conf)
if err != nil {
return nil, errors.Wrapf(err, "could not turn channel application profile into application group")
return nil, errors.Wrapf(err, "could not turn parse profile into channel group")
}
var template, newChannelGroup *cb.ConfigGroup
newChannelGroup = &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
channelconfig.ApplicationGroupKey: ag,
},
}
// Assume the orgs have not been modified
template = proto.Clone(newChannelGroup).(*cb.ConfigGroup)
template.Groups[channelconfig.ApplicationGroupKey].Values = nil
template.Groups[channelconfig.ApplicationGroupKey].Policies = nil
updt, err := update.Compute(&cb.Config{ChannelGroup: template}, &cb.Config{ChannelGroup: newChannelGroup})
updt, err := update.Compute(&cb.Config{ChannelGroup: templateConfig}, &cb.Config{ChannelGroup: newChannelGroup})
if err != nil {
return nil, errors.Wrapf(err, "could not compute update")
}
......@@ -414,9 +401,33 @@ func NewChannelCreateConfigUpdate(channelID string, conf *genesisconfig.Profile)
return updt, nil
}
// DefaultConfigTemplate generates a config template based on the assumption that
// the input profile is a channel creation template and no system channel context
// is available.
func DefaultConfigTemplate(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
channelGroup, err := NewChannelGroup(conf)
if err != nil {
return nil, errors.WithMessage(err, "error parsing configuration")
}
if _, ok := channelGroup.Groups[channelconfig.ApplicationGroupKey]; !ok {
return nil, errors.New("channel template configs must contain an application section")
}
channelGroup.Groups[channelconfig.ApplicationGroupKey].Values = nil
channelGroup.Groups[channelconfig.ApplicationGroupKey].Policies = nil
return channelGroup, nil
}
// MakeChannelCreationTransaction is a handy utility function for creating transactions for channel creation
func MakeChannelCreationTransaction(channelID string, signer crypto.LocalSigner, conf *genesisconfig.Profile) (*cb.Envelope, error) {
newChannelConfigUpdate, err := NewChannelCreateConfigUpdate(channelID, conf)
defaultTemplate, err := DefaultConfigTemplate(conf)
if err != nil {
return nil, errors.WithMessage(err, "default template config generation failed")
}
newChannelConfigUpdate, err := NewChannelCreateConfigUpdate(channelID, conf, defaultTemplate)
if err != nil {
return nil, errors.Wrap(err, "config update generation failure")
}
......
......@@ -100,9 +100,9 @@ var _ = Describe("Encoder", func() {
conf.Orderer = nil
})
It("returns an error", func() {
It("handles it gracefully", func() {
_, err := encoder.NewChannelGroup(conf)
Expect(err).To(MatchError("missing orderer config section"))
Expect(err).NotTo(HaveOccurred())
})
})
})
......@@ -564,7 +564,8 @@ var _ = Describe("Encoder", func() {
Describe("ChannelCreationOperations", func() {
var (
conf *genesisconfig.Profile
conf *genesisconfig.Profile
template *cb.ConfigGroup
)
BeforeEach(func() {
......@@ -587,11 +588,15 @@ var _ = Describe("Encoder", func() {
},
},
}
var err error
template, err = encoder.DefaultConfigTemplate(conf)
Expect(err).NotTo(HaveOccurred())
})
Describe("NewChannelCreateConfigUpdate", func() {
It("translates the config into a config group", func() {
cg, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf)
cg, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
Expect(err).NotTo(HaveOccurred())
Expect(proto.Equal(&cb.ConfigUpdate{
ChannelId: "channel-id",
......@@ -640,6 +645,40 @@ var _ = Describe("Encoder", func() {
}, cg)).To(BeTrue())
})
Context("when the template configuration is not the default", func() {
BeforeEach(func() {
differentConf := &genesisconfig.Profile{
Consortium: "MyConsortium",
Application: &genesisconfig.Application{
Organizations: []*genesisconfig.Organization{
{
MSPDir: "../../../../sampleconfig/msp",
ID: "SampleMSP",
MSPType: "bccsp",
Name: "SampleOrg",
AnchorPeers: []*genesisconfig.AnchorPeer{
{
Host: "hostname",
Port: 5555,
},
},
},
},
},
}
var err error
template, err = encoder.DefaultConfigTemplate(differentConf)
Expect(err).NotTo(HaveOccurred())
})
It("reflects the additional modifications designated by the channel creation profile", func() {
cg, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
Expect(err).NotTo(HaveOccurred())
Expect(cg.WriteSet.Groups["Application"].Groups["SampleOrg"].Values["AnchorPeers"].Version).To(Equal(uint64(1)))
})
})
Context("when the application config is bad", func() {
BeforeEach(func() {
conf.Application.Policies = map[string]*genesisconfig.Policy{
......@@ -650,8 +689,8 @@ var _ = Describe("Encoder", func() {
})
It("returns an error", func() {
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf)
Expect(err).To(MatchError("could not turn channel application profile into application group: error adding policies to application group: unknown policy type: bad-type"))
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
Expect(err).To(MatchError("could not turn parse profile into channel group: could not create application group: error adding policies to application group: unknown policy type: bad-type"))
})
Context("when the application config is missing", func() {
......@@ -660,7 +699,7 @@ var _ = Describe("Encoder", func() {
})
It("returns an error", func() {
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf)
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
Expect(err).To(MatchError("cannot define a new channel with no Application section"))
})
})
......@@ -672,7 +711,7 @@ var _ = Describe("Encoder", func() {
})
It("returns an error", func() {
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf)
_, err := encoder.NewChannelCreateConfigUpdate("channel-id", conf, template)
Expect(err).To(MatchError("cannot define a new channel with no Consortium value"))
})
})
......@@ -705,6 +744,17 @@ var _ = Describe("Encoder", func() {
Expect(fakeSigner.SignArgsForCall(0)).To(Equal(util.ConcatenateBytes(configUpdateEnv.Signatures[0].SignatureHeader, configUpdateEnv.ConfigUpdate)))
})
Context("when a default config cannot be generated", func() {
BeforeEach(func() {
conf.Application = nil
})
It("wraps and returns the error", func() {
_, err := encoder.MakeChannelCreationTransaction("channel-id", fakeSigner, conf)
Expect(err).To(MatchError("default template config generation failed: channel template configs must contain an application section"))
})
})
Context("when the signer cannot create the signature header", func() {
BeforeEach(func() {
fakeSigner.NewSignatureHeaderReturns(nil, fmt.Errorf("signature-header-error"))
......@@ -745,6 +795,75 @@ var _ = Describe("Encoder", func() {
})
})
})
Describe("DefaultConfigTemplate", func() {
var (
conf *genesisconfig.Profile
)
BeforeEach(func() {
conf = &genesisconfig.Profile{
Orderer: &genesisconfig.Orderer{
OrdererType: "solo",
},
Application: &genesisconfig.Application{
Policies: map[string]*genesisconfig.Policy{
"IgnoredPolicy": {
Type: "ImplicitMeta",
Rule: "ANY Admins",
},
},
Organizations: []*genesisconfig.Organization{
{
MSPDir: "../../../../sampleconfig/msp",
ID: "Org1MSP",
MSPType: "bccsp",
Name: "Org1",
},
{
MSPDir: "../../../../sampleconfig/msp",
ID: "Org2MSP",
MSPType: "bccsp",
Name: "Org2",
},
},
},
}
})
It("returns the default config tempalte", func() {
cg, err := encoder.DefaultConfigTemplate(conf)
Expect(err).NotTo(HaveOccurred())
Expect(len(cg.Groups)).To(Equal(2))
Expect(cg.Groups["Orderer"]).NotTo(BeNil())
Expect(cg.Groups["Application"]).NotTo(BeNil())
Expect(cg.Groups["Application"].Policies).To(BeEmpty())
Expect(cg.Groups["Application"].Values).To(BeEmpty())
Expect(len(cg.Groups["Application"].Groups)).To(Equal(2))
})
Context("when the config cannot be turned into a channel group", func() {
BeforeEach(func() {
conf.Orderer.OrdererType = "garbage"
})
It("wraps and returns the error", func() {
_, err := encoder.DefaultConfigTemplate(conf)
Expect(err).To(MatchError("error parsing configuration: could not create orderer group: unknown orderer type: garbage"))
})
})
Context("when the application config is nil", func() {
BeforeEach(func() {
conf.Application = nil
})
It("returns an error", func() {
_, err := encoder.DefaultConfigTemplate(conf)
Expect(err).To(MatchError("channel template configs must contain an application section"))
})
})
})
})
Describe("Bootstrapper", func() {
......
......@@ -33,6 +33,9 @@ var logger = flogging.MustGetLogger("common.tools.configtxgen")
func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error {
pgen := encoder.New(config)
logger.Info("Generating genesis block")
if config.Orderer == nil {
return errors.Errorf("refusing to generate block which is missing orderer section")
}
if config.Consortiums == nil {
logger.Warning("Genesis block does not contain a consortiums group definition. This block cannot be used for orderer bootstrap.")
}
......
......@@ -63,7 +63,7 @@ func TestMissingOrdererSection(t *testing.T) {
config := configtxgentest.Load(genesisconfig.SampleInsecureSoloProfile)
config.Orderer = nil
assert.Panics(t, func() { doOutputBlock(config, "foo", blockDest) }, "Missing orderer section")
assert.Error(t, doOutputBlock(config, "foo", blockDest), "Missing orderer section")
}
func TestMissingConsortiumSection(t *testing.T) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment