Skip to content

Commit

Permalink
[FAB-2176] Add ConfigUpdate proto
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2176

In order to stabilize the protos, the ConfigUpdate protos need to go in
first. The existing code can be adapted simply to depend on a
ConfigUpdate write set which includes the entire config. Then, the
actual partial config updates can be built on top of it.

Change-Id: Ib718ebb056c64ae27c84088ca0da82f73d632e54
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Feb 14, 2017
1 parent 28e0d18 commit c16f5b3
Show file tree
Hide file tree
Showing 14 changed files with 287 additions and 152 deletions.
26 changes: 19 additions & 7 deletions common/configtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ func computeSequence(configGroup *cb.ConfigGroup) uint64 {

// computeChannelIdAndSequence returns the chain id and the sequence number for a config envelope
// or an error if there is a problem with the config envelope
func computeChannelIdAndSequence(config *cb.Config) (string, uint64, error) {
if config.Channel == nil {
func computeChannelIdAndSequence(config *cb.ConfigUpdate) (string, uint64, error) {
if config.WriteSet == nil {
return "", 0, errors.New("Empty envelope unsupported")
}

Expand All @@ -98,7 +98,7 @@ func computeChannelIdAndSequence(config *cb.Config) (string, uint64, error) {
return "", 0, err
}

m := computeSequence(config.Channel)
m := computeSequence(config.WriteSet)

return chainID, m, nil
}
Expand Down Expand Up @@ -134,7 +134,13 @@ func validateChainID(chainID string) error {
}

func NewManagerImpl(configtx *cb.ConfigEnvelope, initializer api.Initializer, callOnUpdate []func(api.Manager)) (api.Manager, error) {
config, err := UnmarshalConfig(configtx.Config)
// XXX as a temporary hack to get the new protos working, we assume entire config is always in the ConfigUpdate.WriteSet

if configtx.LastUpdate == nil {
return nil, fmt.Errorf("Must have ConfigEnvelope.LastUpdate set")
}

config, err := UnmarshalConfigUpdate(configtx.LastUpdate.ConfigUpdate)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -240,7 +246,13 @@ func (cm *configManager) recurseConfig(result map[string]comparable, path []stri
}

func (cm *configManager) processConfig(configtx *cb.ConfigEnvelope) (configMap map[string]comparable, err error) {
config, err := UnmarshalConfig(configtx.Config)
// XXX as a temporary hack to get the new protos working, we assume entire config is always in the ConfigUpdate.WriteSet

if configtx.LastUpdate == nil {
return nil, fmt.Errorf("Must have ConfigEnvelope.LastUpdate set")
}

config, err := UnmarshalConfigUpdate(configtx.LastUpdate.ConfigUpdate)
if err != nil {
return nil, err
}
Expand All @@ -250,7 +262,7 @@ func (cm *configManager) processConfig(configtx *cb.ConfigEnvelope) (configMap m
return nil, err
}

signedData, err := configtx.AsSignedData()
signedData, err := configtx.LastUpdate.AsSignedData()
if err != nil {
return nil, err
}
Expand All @@ -274,7 +286,7 @@ func (cm *configManager) processConfig(configtx *cb.ConfigEnvelope) (configMap m

configMap = make(map[string]comparable)

if err := cm.recurseConfig(configMap, []string{}, config.Channel); err != nil {
if err := cm.recurseConfig(configMap, []string{}, config.WriteSet); err != nil {
return nil, err
}

Expand Down
66 changes: 36 additions & 30 deletions common/configtx/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,21 @@ func makeConfigPair(id, modificationPolicy string, lastModified uint64, data []b
}
}

func makeMarshaledConfig(chainID string, configPairs ...*configPair) []byte {
func makeConfigUpdateEnvelope(chainID string, configPairs ...*configPair) *cb.ConfigUpdateEnvelope {
values := make(map[string]*cb.ConfigValue)
for _, pair := range configPairs {
values[pair.key] = pair.value
}

config := &cb.Config{
config := &cb.ConfigUpdate{
Header: &cb.ChannelHeader{ChannelId: chainID},
Channel: &cb.ConfigGroup{
WriteSet: &cb.ConfigGroup{
Values: values,
},
}
return utils.MarshalOrPanic(config)
return &cb.ConfigUpdateEnvelope{
ConfigUpdate: utils.MarshalOrPanic(config),
}
}

func TestCallback(t *testing.T) {
Expand All @@ -78,7 +80,7 @@ func TestCallback(t *testing.T) {
}

cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), []func(api.Manager){callback})

if err != nil {
Expand All @@ -93,15 +95,15 @@ func TestCallback(t *testing.T) {
// TestDifferentChainID tests that a config update for a different chain ID fails
func TestDifferentChainID(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
t.Fatalf("Error constructing config manager: %s", err)
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig("wrongChain", makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope("wrongChain", makeConfigPair("foo", "foo", 1, []byte("foo"))),
}

err = cm.Validate(newConfig)
Expand All @@ -118,15 +120,15 @@ func TestDifferentChainID(t *testing.T) {
// TestOldConfigReplay tests that resubmitting a config for a sequence number which is not newer is ignored
func TestOldConfigReplay(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
t.Fatalf("Error constructing config manager: %s", err)
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}

err = cm.Validate(newConfig)
Expand All @@ -143,7 +145,9 @@ func TestOldConfigReplay(t *testing.T) {
// TestInvalidInitialConfigByStructure tests to make sure that if the config contains corrupted config that construction results in error
func TestInvalidInitialConfigByStructure(t *testing.T) {
_, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: []byte("Corrupted"),
LastUpdate: &cb.ConfigUpdateEnvelope{
ConfigUpdate: []byte("Corrupted"),
},
}, defaultInitializer(), nil)

if err == nil {
Expand All @@ -154,15 +158,15 @@ func TestInvalidInitialConfigByStructure(t *testing.T) {
// TestValidConfigChange tests the happy path of updating a config value with no defaultModificationPolicy
func TestValidConfigChange(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
t.Fatalf("Error constructing config manager: %s", err)
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
}

err = cm.Validate(newConfig)
Expand All @@ -180,15 +184,15 @@ func TestValidConfigChange(t *testing.T) {
// config values while advancing another
func TestConfigChangeRegressedSequence(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
t.Fatalf("Error constructing config manager: %s", err)
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 0, []byte("foo")),
makeConfigPair("bar", "bar", 2, []byte("bar")),
Expand All @@ -210,15 +214,15 @@ func TestConfigChangeRegressedSequence(t *testing.T) {
// config values while advancing another
func TestConfigChangeOldSequence(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
t.Fatalf("Error constructing config manager: %s", err)
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 2, []byte("foo")),
makeConfigPair("bar", "bar", 1, []byte("bar")),
Expand All @@ -240,7 +244,7 @@ func TestConfigChangeOldSequence(t *testing.T) {
// by omitting them in the new config
func TestConfigImplicitDelete(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 0, []byte("foo")),
makeConfigPair("bar", "bar", 0, []byte("bar")),
Expand All @@ -252,7 +256,7 @@ func TestConfigImplicitDelete(t *testing.T) {
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("bar", "bar", 1, []byte("bar")),
),
Expand All @@ -272,7 +276,7 @@ func TestConfigImplicitDelete(t *testing.T) {
// TestEmptyConfigUpdate tests to make sure that an empty config is rejected as an update
func TestEmptyConfigUpdate(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), nil)

if err != nil {
Expand All @@ -297,7 +301,7 @@ func TestEmptyConfigUpdate(t *testing.T) {
// increasing the config item's LastModified
func TestSilentConfigModification(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 0, []byte("foo")),
makeConfigPair("bar", "bar", 0, []byte("bar")),
Expand All @@ -309,7 +313,7 @@ func TestSilentConfigModification(t *testing.T) {
}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 0, []byte("different")),
makeConfigPair("bar", "bar", 1, []byte("bar")),
Expand All @@ -333,7 +337,7 @@ func TestInvalidInitialConfigByPolicy(t *testing.T) {
initializer := defaultInitializer()
initializer.Resources.PolicyManagerVal.Policy.Err = fmt.Errorf("err")
_, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, initializer, nil)

if err == nil {
Expand All @@ -346,7 +350,7 @@ func TestInvalidInitialConfigByPolicy(t *testing.T) {
func TestConfigChangeViolatesPolicy(t *testing.T) {
initializer := defaultInitializer()
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, initializer, nil)

if err != nil {
Expand All @@ -356,7 +360,7 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
initializer.Resources.PolicyManagerVal.Policy.Err = fmt.Errorf("err")

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
}

err = cm.Validate(newConfig)
Expand All @@ -375,7 +379,7 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
func TestUnchangedConfigViolatesPolicy(t *testing.T) {
initializer := defaultInitializer()
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, initializer, nil)

if err != nil {
Expand All @@ -387,7 +391,7 @@ func TestUnchangedConfigViolatesPolicy(t *testing.T) {
initializer.Resources.PolicyManagerVal.PolicyMap["foo"] = &mockpolicies.Policy{Err: fmt.Errorf("err")}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(
LastUpdate: makeConfigUpdateEnvelope(
defaultChain,
makeConfigPair("foo", "foo", 0, []byte("foo")),
makeConfigPair("bar", "bar", 1, []byte("foo")),
Expand All @@ -410,7 +414,7 @@ func TestUnchangedConfigViolatesPolicy(t *testing.T) {
func TestInvalidProposal(t *testing.T) {
initializer := defaultInitializer()
cm, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, initializer, nil)

if err != nil {
Expand All @@ -420,7 +424,7 @@ func TestInvalidProposal(t *testing.T) {
initializer.HandlerVal = &mockconfigtx.Handler{ErrorForProposeConfig: fmt.Errorf("err")}

newConfig := &cb.ConfigEnvelope{
Config: makeMarshaledConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
}

err = cm.Validate(newConfig)
Expand All @@ -440,7 +444,9 @@ func TestMissingHeader(t *testing.T) {
group.Values["foo"] = &cb.ConfigValue{}
data := utils.MarshalOrPanic(&cb.Config{Channel: group})
_, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: data,
LastUpdate: &cb.ConfigUpdateEnvelope{
ConfigUpdate: data,
},
}, defaultInitializer(), nil)

if err == nil {
Expand All @@ -451,7 +457,7 @@ func TestMissingHeader(t *testing.T) {
// TestMissingChainID checks that a config item with a missing chainID causes the config to be rejected
func TestMissingChainID(t *testing.T) {
_, err := NewManagerImpl(&cb.ConfigEnvelope{
Config: makeMarshaledConfig("", makeConfigPair("foo", "foo", 0, []byte("foo"))),
LastUpdate: makeConfigUpdateEnvelope("", makeConfigPair("foo", "foo", 0, []byte("foo"))),
}, defaultInitializer(), nil)

if err == nil {
Expand Down
Loading

0 comments on commit c16f5b3

Please sign in to comment.