Skip to content

Commit

Permalink
[FAB-1856] Add configtx callback events
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1856

The gossip team requires a way to be notified when the channel
configuration changes.  This changeset allows the configtx manager to be
constructed with a slice of functions to call when a new configuration
is committed.

Change-Id: Ib318e271b7c00685117d10d0982ccc8a09a9801e
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Jan 26, 2017
1 parent 9f07b96 commit b225806
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 22 deletions.
10 changes: 8 additions & 2 deletions common/configtx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type configurationManager struct {
sequence uint64
chainID string
configuration map[cb.ConfigurationItem_ConfigurationType]map[string]*cb.ConfigurationItem
callOnUpdate []func(Manager)
}

// computeChainIDAndSequence returns the chain id and the sequence number for a configuration envelope
Expand Down Expand Up @@ -119,8 +120,9 @@ func computeChainIDAndSequence(configtx *cb.ConfigurationEnvelope) (string, uint
return chainID, m, nil
}

// NewManagerImpl creates a new Manager unless an error is encountered
func NewManagerImpl(configtx *cb.ConfigurationEnvelope, initializer Initializer) (Manager, error) {
// NewManagerImpl creates a new Manager unless an error is encountered, each element of the callOnUpdate slice
// is invoked when a new configuration is committed
func NewManagerImpl(configtx *cb.ConfigurationEnvelope, initializer Initializer, callOnUpdate []func(Manager)) (Manager, error) {
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
if _, ok := initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)]; !ok {
return nil, errors.New("Must supply a handler for all known types")
Expand All @@ -137,6 +139,7 @@ func NewManagerImpl(configtx *cb.ConfigurationEnvelope, initializer Initializer)
sequence: seq - 1,
chainID: chainID,
configuration: makeConfigMap(),
callOnUpdate: callOnUpdate,
}

err = cm.Apply(configtx)
Expand Down Expand Up @@ -175,6 +178,9 @@ func (cm *configurationManager) commitHandlers() {
for ctype := range cb.ConfigurationItem_ConfigurationType_name {
cm.Initializer.Handlers()[cb.ConfigurationItem_ConfigurationType(ctype)].CommitConfig()
}
for _, callback := range cm.callOnUpdate {
callback(cm)
}
}

func (cm *configurationManager) processConfig(configtx *cb.ConfigurationEnvelope) (configMap map[cb.ConfigurationItem_ConfigurationType]map[string]*cb.ConfigurationItem, err error) {
Expand Down
53 changes: 36 additions & 17 deletions common/configtx/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,37 @@ func makeSignedConfigurationItem(id, modificationPolicy string, lastModified uin
func TestOmittedHandler(t *testing.T) {
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: map[cb.ConfigurationItem_ConfigurationType]Handler{}})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: map[cb.ConfigurationItem_ConfigurationType]Handler{}}, nil)

if err == nil {
t.Fatal("Should have failed to construct manager because handlers were missing")
}
}

func TestCallback(t *testing.T) {
var calledBack Manager
callback := func(m Manager) {
calledBack = m
}

cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, []func(Manager){callback})

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

if calledBack != cm {
t.Fatalf("Should have called back with the correct manager")
}
}

// TestWrongChainID tests that a configuration update for a different chain ID fails
func TestWrongChainID(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -128,7 +147,7 @@ func TestWrongChainID(t *testing.T) {
func TestOldConfigReplay(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -155,7 +174,7 @@ func TestInvalidInitialConfigByStructure(t *testing.T) {
entries[0].ConfigurationItem = []byte("Corrupted")
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: entries,
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err == nil {
t.Fatal("Should have failed to construct configuration by policy")
Expand All @@ -166,7 +185,7 @@ func TestInvalidInitialConfigByStructure(t *testing.T) {
func TestValidConfigChange(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -192,7 +211,7 @@ func TestValidConfigChange(t *testing.T) {
func TestConfigChangeRegressedSequence(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -221,7 +240,7 @@ func TestConfigChangeRegressedSequence(t *testing.T) {
func TestConfigChangeOldSequence(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 1, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -253,7 +272,7 @@ func TestConfigImplicitDelete(t *testing.T) {
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain),
makeSignedConfigurationItem("bar", "bar", 0, []byte("bar"), defaultChain),
},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand All @@ -280,7 +299,7 @@ func TestConfigImplicitDelete(t *testing.T) {
func TestEmptyConfigUpdate(t *testing.T) {
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -308,7 +327,7 @@ func TestSilentConfigModification(t *testing.T) {
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain),
makeSignedConfigurationItem("bar", "bar", 0, []byte("bar"), defaultChain),
},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -337,7 +356,7 @@ func TestSilentConfigModification(t *testing.T) {
func TestInvalidInitialConfigByPolicy(t *testing.T) {
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{policyResult: fmt.Errorf("err")}}, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{policyResult: fmt.Errorf("err")}}, HandlersVal: defaultHandlers()}, nil)

if err == nil {
t.Fatal("Should have failed to construct configuration by policy")
Expand All @@ -350,7 +369,7 @@ func TestConfigChangeViolatesPolicy(t *testing.T) {
mpm := &mockPolicyManager{}
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -379,7 +398,7 @@ func TestUnchangedConfigViolatesPolicy(t *testing.T) {
mpm := &mockPolicyManager{}
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()})
}, &mockconfigtx.Initializer{PolicyManagerVal: mpm, HandlersVal: defaultHandlers()}, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -424,7 +443,7 @@ func TestInvalidProposal(t *testing.T) {
initializer := &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers}
cm, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), defaultChain)},
}, initializer)
}, initializer, nil)

if err != nil {
t.Fatalf("Error constructing configuration manager: %s", err)
Expand Down Expand Up @@ -455,7 +474,7 @@ func TestMissingHeader(t *testing.T) {
data, _ := proto.Marshal(configItem)
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{&cb.SignedConfigurationItem{ConfigurationItem: data}},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers}, nil)

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand All @@ -467,7 +486,7 @@ func TestMissingChainID(t *testing.T) {
handlers := defaultHandlers()
_, err := NewManagerImpl(&cb.ConfigurationEnvelope{
Items: []*cb.SignedConfigurationItem{makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "")},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers}, nil)

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand All @@ -482,7 +501,7 @@ func TestMismatchedChainID(t *testing.T) {
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "chain1"),
makeSignedConfigurationItem("foo", "foo", 0, []byte("foo"), "chain2"),
},
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers})
}, &mockconfigtx.Initializer{PolicyManagerVal: &mockPolicyManager{&mockPolicy{}}, HandlersVal: handlers}, nil)

if err == nil {
t.Error("Should have errored creating the configuration manager because of the missing header")
Expand Down
2 changes: 1 addition & 1 deletion common/configtx/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func MakeChainCreationTransaction(creationPolicy string, chainID string, signer
return nil, err
}

manager, err := NewManagerImpl(&cb.ConfigurationEnvelope{Items: items}, NewInitializer())
manager, err := NewManagerImpl(&cb.ConfigurationEnvelope{Items: items}, NewInitializer(), nil)

newChainTemplate := NewChainCreationTemplate(creationPolicy, manager.ChainConfig().HashingAlgorithm(), composite)
signedConfigItems, err := newChainTemplate.Items(chainID)
Expand Down
2 changes: 1 addition & 1 deletion core/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {

configtxInitializer := configtx.NewInitializer()
configtxInitializer.Handlers()[common.ConfigurationItem_Peer] = sharedConfigHandler
configtxManager, err := configtx.NewManagerImpl(configEnvelope, configtxInitializer)
configtxManager, err := configtx.NewManagerImpl(configEnvelope, configtxInitializer, nil)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion orderer/multichain/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func newConfigResources(configEnvelope *cb.ConfigurationEnvelope) (*configResour
initializer := configtx.NewInitializer()
initializer.Handlers()[cb.ConfigurationItem_Orderer] = sharedConfigManager

configManager, err := configtx.NewManagerImpl(configEnvelope, initializer)
configManager, err := configtx.NewManagerImpl(configEnvelope, initializer, nil)
if err != nil {
return nil, fmt.Errorf("Error unpacking configuration transaction: %s", err)
}
Expand Down

0 comments on commit b225806

Please sign in to comment.