Skip to content

Commit

Permalink
[FAB-2349] Change channel create to CONFIG_UPDATE
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2349

Channel creation is currently being done via a CONFIG transaction but
this needs to be modified to be a CONFIG_UPDATE transaction.  This will
enable future support of partial config channel creation.

Change-Id: I7bc116120adf411f0020a827fcd6c7a36d0d8b66
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Feb 18, 2017
1 parent b78e929 commit 4887bf4
Show file tree
Hide file tree
Showing 17 changed files with 252 additions and 172 deletions.
7 changes: 5 additions & 2 deletions common/configtx/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ type Manager interface {
Resources

// Apply attempts to apply a configtx to become the new config
Apply(configtx *cb.Envelope) error
Apply(configEnv *cb.ConfigEnvelope) error

// Validate attempts to apply a configtx to become the new config
Validate(configEnv *cb.ConfigEnvelope) error

// Validate attempts to validate a new configtx against the current config state
Validate(configtx *cb.Envelope) error
ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error)

// ConfigEnvelope returns the *cb.ConfigEnvelope from the last successful Apply
ConfigEnvelope() *cb.ConfigEnvelope
Expand Down
75 changes: 56 additions & 19 deletions common/configtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package configtx

import (
"fmt"
"reflect"
"regexp"

"github.com/hyperledger/fabric/common/configtx/api"
Expand Down Expand Up @@ -146,49 +147,92 @@ func (cm *configManager) commitCallbacks() {
}

// Validate attempts to validate a new configtx against the current config state
func (cm *configManager) Validate(configtx *cb.Envelope) error {
// It requires an Envelope of type CONFIG_UPDATE
func (cm *configManager) ProposeConfigUpdate(configtx *cb.Envelope) (*cb.ConfigEnvelope, error) {
configUpdateEnv, err := envelopeToConfigUpdate(configtx)
if err != nil {
return err
return nil, err
}

configMap, err := cm.authorizeUpdate(configUpdateEnv)
if err != nil {
return err
return nil, err
}

channelGroup, err := configMapToConfig(configMap)
if err != nil {
return fmt.Errorf("Could not turn configMap back to channelGroup: %s", err)
return nil, fmt.Errorf("Could not turn configMap back to channelGroup: %s", err)
}

result, err := cm.processConfig(channelGroup)
if err != nil {
return err
return nil, err
}

result.rollback()
return nil

return &cb.ConfigEnvelope{
Config: &cb.Config{
Header: &cb.ChannelHeader{
ChannelId: cm.chainID,
},
Channel: channelGroup,
},
LastUpdate: configtx,
}, nil
}

// Apply attempts to apply a configtx to become the new config
func (cm *configManager) Apply(configtx *cb.Envelope) error {
configUpdateEnv, err := envelopeToConfigUpdate(configtx)
func (cm *configManager) prepareApply(configEnv *cb.ConfigEnvelope) (map[string]comparable, *configResult, error) {
if configEnv == nil {
return nil, nil, fmt.Errorf("Attempted to apply config with nil envelope")
}

configUpdateEnv, err := envelopeToConfigUpdate(configEnv.LastUpdate)
if err != nil {
return err
return nil, nil, err
}

configMap, err := cm.authorizeUpdate(configUpdateEnv)
if err != nil {
return err
return nil, nil, err
}

channelGroup, err := configMapToConfig(configMap)
if err != nil {
return fmt.Errorf("Could not turn configMap back to channelGroup: %s", err)
return nil, nil, fmt.Errorf("Could not turn configMap back to channelGroup: %s", err)
}

if configEnv.Config == nil {
return nil, nil, fmt.Errorf("Config cannot be nil")
}

if !reflect.DeepEqual(channelGroup, configEnv.Config.Channel) {
return nil, nil, fmt.Errorf("ConfigEnvelope LastUpdate did not produce the supplied config result")
}

result, err := cm.processConfig(channelGroup)
if err != nil {
return nil, nil, err
}

return configMap, result, nil
}

// Validate simulates applying a ConfigEnvelope to become the new config
func (cm *configManager) Validate(configEnv *cb.ConfigEnvelope) error {
_, result, err := cm.prepareApply(configEnv)
if err != nil {
return err
}

result.rollback()

return nil
}

// Apply attempts to apply a ConfigEnvelope to become the new config
func (cm *configManager) Apply(configEnv *cb.ConfigEnvelope) error {
configMap, result, err := cm.prepareApply(configEnv)
if err != nil {
return err
}
Expand All @@ -199,13 +243,6 @@ func (cm *configManager) Apply(configtx *cb.Envelope) error {
cm.config = configMap
cm.sequence++

cm.configEnv = &cb.ConfigEnvelope{
Config: &cb.Config{
// XXX add header
Channel: channelGroup,
},
LastUpdate: configtx,
}
return nil
}

Expand Down
99 changes: 32 additions & 67 deletions common/configtx/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,9 @@ func TestDifferentChainID(t *testing.T) {

newConfig := makeConfigUpdateEnvelope("wrongChain", makeConfigPair("foo", "foo", 1, []byte("foo")))

err = cm.Validate(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored when validating a new config set the wrong chain ID")
}

err = cm.Apply(newConfig)
if err == nil {
t.Error("Should have errored when applying a new config with the wrong chain ID")
t.Error("Should have errored when proposing a new config set the wrong chain ID")
}
}

Expand All @@ -157,14 +152,9 @@ func TestOldConfigReplay(t *testing.T) {

newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo")))

err = cm.Validate(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored when validating a config that is not a newer sequence number")
}

err = cm.Apply(newConfig)
if err == nil {
t.Error("Should have errored when applying a config that is not a newer sequence number")
t.Error("Should have errored when proposing a config that is not a newer sequence number")
}
}

Expand All @@ -180,12 +170,17 @@ func TestValidConfigChange(t *testing.T) {

newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo")))

err = cm.Validate(newConfig)
configEnv, err := cm.ProposeConfigUpdate(newConfig)
if err != nil {
t.Errorf("Should not have errored proposing config: %s", err)
}

err = cm.Validate(configEnv)
if err != nil {
t.Errorf("Should not have errored validating config: %s", err)
}

err = cm.Apply(newConfig)
err = cm.Apply(configEnv)
if err != nil {
t.Errorf("Should not have errored applying config: %s", err)
}
Expand All @@ -208,14 +203,9 @@ func TestConfigChangeRegressedSequence(t *testing.T) {
makeConfigPair("bar", "bar", 2, []byte("bar")),
)

err = cm.Validate(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored validating config because foo's sequence number regressed")
}

err = cm.Apply(newConfig)
if err == nil {
t.Error("Should have errored applying config because foo's sequence number regressed")
t.Error("Should have errored proposing config because foo's sequence number regressed")
}
}

Expand All @@ -236,14 +226,9 @@ func TestConfigChangeOldSequence(t *testing.T) {
makeConfigPair("bar", "bar", 1, []byte("bar")),
)

err = cm.Validate(newConfig)
if err == nil {
t.Error("Should have errored validating config because bar was new but its sequence number was old")
}

err = cm.Apply(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored applying config because bar was new but its sequence number was old")
t.Error("Should have errored proposing config because bar was new but its sequence number was old")
}
}

Expand All @@ -267,14 +252,9 @@ func TestConfigImplicitDelete(t *testing.T) {
makeConfigPair("bar", "bar", 1, []byte("bar")),
)

err = cm.Validate(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored validating config because foo was implicitly deleted")
}

err = cm.Apply(newConfig)
if err == nil {
t.Error("Should have errored applying config because foo was implicitly deleted")
t.Error("Should have errored proposing config because foo was implicitly deleted")
}
}

Expand All @@ -290,14 +270,9 @@ func TestEmptyConfigUpdate(t *testing.T) {

newConfig := &cb.Envelope{}

err = cm.Validate(newConfig)
if err == nil {
t.Error("Should not errored validating config because new config is empty")
}

err = cm.Apply(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should not errored applying config because new config is empty")
t.Error("Should not errored proposing config because new config is empty")
}
}

Expand All @@ -323,14 +298,9 @@ func TestSilentConfigModification(t *testing.T) {
makeConfigPair("bar", "bar", 1, []byte("bar")),
)

err = cm.Validate(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should not errored validating config because foo was silently modified (despite modification allowed by policy)")
}

err = cm.Apply(newConfig)
if err == nil {
t.Error("Should not errored applying config because foo was silently modified (despite modification allowed by policy)")
t.Error("Should have errored proposing config because foo was silently modified (despite modification allowed by policy)")
}
}

Expand All @@ -350,14 +320,9 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {

newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo")))

err = cm.Validate(newConfig)
if err == nil {
t.Error("Should have errored validating config because policy rejected modification")
}

err = cm.Apply(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored applying config because policy rejected modification")
t.Error("Should have errored proposing config because policy rejected modification")
}
}

Expand All @@ -383,12 +348,17 @@ func TestUnchangedConfigViolatesPolicy(t *testing.T) {
makeConfigPair("bar", "bar", 1, []byte("foo")),
)

err = cm.Validate(newConfig)
configEnv, err := cm.ProposeConfigUpdate(newConfig)
if err != nil {
t.Errorf("Should not have errored proposing config, but got %s", err)
}

err = cm.Validate(configEnv)
if err != nil {
t.Errorf("Should not have errored validating config, but got %s", err)
}

err = cm.Apply(newConfig)
err = cm.Apply(configEnv)
if err != nil {
t.Errorf("Should not have errored applying config, but got %s", err)
}
Expand All @@ -410,14 +380,9 @@ func TestInvalidProposal(t *testing.T) {

newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo")))

err = cm.Validate(newConfig)
if err == nil {
t.Error("Should have errored validating config because the handler rejected it")
}

err = cm.Apply(newConfig)
_, err = cm.ProposeConfigUpdate(newConfig)
if err == nil {
t.Error("Should have errored applying config because the handler rejected it")
t.Error("Should have errored proposing config because the handler rejected it")
}
}

Expand Down
28 changes: 2 additions & 26 deletions common/configtx/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,34 +195,10 @@ func MakeChainCreationTransaction(creationPolicy string, chainID string, signer
return nil, err
}

configUpdate, err := UnmarshalConfigUpdate(newConfigUpdateEnv.ConfigUpdate)
if err != nil {
return nil, err
}

newConfigEnv := &cb.ConfigEnvelope{
// Config is an XXX temporary workaround until the orderer generates the real configtx from the WriteSet
Config: &cb.Config{
Header: configUpdate.Header,
Channel: configUpdate.WriteSet,
},
LastUpdate: &cb.Envelope{
Payload: utils.MarshalOrPanic(&cb.Payload{
Header: &cb.Header{
ChannelHeader: &cb.ChannelHeader{
ChannelId: chainID,
Type: int32(cb.HeaderType_CONFIG_UPDATE),
},
},
Data: utils.MarshalOrPanic(newConfigUpdateEnv),
}),
},
}

payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG, msgVersion, chainID, epoch)
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, msgVersion, chainID, epoch)
payloadSignatureHeader := utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())
payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader)
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(newConfigEnv)}
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(newConfigUpdateEnv)}
paylBytes := utils.MarshalOrPanic(payload)

// sign the payload
Expand Down
Loading

0 comments on commit 4887bf4

Please sign in to comment.