Skip to content

Commit 3a61f6b

Browse files
author
Jason Yellick
committed
[FAB-2261] Make Handler creation transactional
https://jira.hyperledger.org/browse/FAB-2261 At the organization level, handlers were being instaniated dynamically, but, the handlers were only being instructed to begin transactions statically. This caused a crash when a dynamically created org handler would be told to process a config item before begin the config transaction. This CR reworks the handler instantiation to be done at the beginning of a transaction. Change-Id: Ifbd2f9adf5809cb9fca3108573f105db4b0d790a Signed-off-by: Jason Yellick <[email protected]>
1 parent 7559dd9 commit 3a61f6b

18 files changed

+264
-216
lines changed

common/cauthdsl/policy_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func makePolicySource(policyResult bool) *cb.Policy {
5757
}
5858

5959
func addPolicy(manager *policies.ManagerImpl, id string, policy *cb.Policy) {
60-
manager.BeginConfig()
60+
manager.BeginConfig(nil)
6161
err := manager.ProposePolicy(id, []string{}, &cb.ConfigPolicy{
6262
Policy: policy,
6363
})

common/configtx/api/api.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ type OrdererConfig interface {
8282
// Handler provides a hook which allows other pieces of code to participate in config proposals
8383
// TODO, this should probably be renamed to ValueHandler
8484
type Handler interface {
85+
Transactional
86+
8587
// ProposeConfig called when config is added to a proposal
8688
ProposeConfig(key string, configValue *cb.ConfigValue) error
8789
}
@@ -129,7 +131,7 @@ type Resources interface {
129131
// Transactional is an interface which allows for an update to be proposed and rolled back
130132
type Transactional interface {
131133
// BeginConfig called when a config proposal is begun
132-
BeginConfig()
134+
BeginConfig(groups []string) ([]Handler, error)
133135

134136
// RollbackConfig called when a config proposal is abandoned
135137
RollbackConfig()
@@ -138,14 +140,6 @@ type Transactional interface {
138140
CommitConfig()
139141
}
140142

141-
// SubInitializer is used downstream from initializer
142-
type SubInitializer interface {
143-
Transactional
144-
145-
// Handler returns the associated value handler for a given config path
146-
Handler(path []string) (Handler, error)
147-
}
148-
149143
// PolicyHandler is used for config updates to policy
150144
type PolicyHandler interface {
151145
Transactional
@@ -156,7 +150,7 @@ type PolicyHandler interface {
156150
// Initializer is used as indirection between Manager and Handler to allow
157151
// for single Handlers to handle multiple paths
158152
type Initializer interface {
159-
SubInitializer
153+
Handler
160154

161155
Resources
162156

common/configtx/handlers/application/organization.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package application
1919
import (
2020
"fmt"
2121

22+
"github.com/hyperledger/fabric/common/configtx/api"
2223
"github.com/hyperledger/fabric/common/configtx/handlers"
2324
mspconfig "github.com/hyperledger/fabric/common/configtx/handlers/msp"
2425
cb "github.com/hyperledger/fabric/protos/common"
@@ -62,18 +63,23 @@ func (oc *ApplicationOrgConfig) AnchorPeers() []*pb.AnchorPeer {
6263
}
6364

6465
// BeginConfig is used to start a new config proposal
65-
func (oc *ApplicationOrgConfig) BeginConfig() {
66+
func (oc *ApplicationOrgConfig) BeginConfig(groups []string) ([]api.Handler, error) {
6667
logger.Debugf("Beginning a possible new org config")
68+
if len(groups) != 0 {
69+
return nil, fmt.Errorf("ApplicationGroup does not support subgroups")
70+
}
6771
if oc.pendingConfig != nil {
6872
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
6973
}
7074
oc.pendingConfig = &applicationOrgConfig{}
75+
return oc.OrgConfig.BeginConfig(groups)
7176
}
7277

7378
// RollbackConfig is used to abandon a new config proposal
7479
func (oc *ApplicationOrgConfig) RollbackConfig() {
7580
logger.Debugf("Rolling back proposed org config")
7681
oc.pendingConfig = nil
82+
oc.OrgConfig.RollbackConfig()
7783
}
7884

7985
// CommitConfig is used to commit a new config proposal
@@ -84,6 +90,7 @@ func (oc *ApplicationOrgConfig) CommitConfig() {
8490
}
8591
oc.config = oc.pendingConfig
8692
oc.pendingConfig = nil
93+
oc.OrgConfig.CommitConfig()
8794
}
8895

8996
// ProposeConfig is used to add new config to the config proposal

common/configtx/handlers/application/organization_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ func groupToKeyValue(configGroup *cb.ConfigGroup) (string, *cb.ConfigValue) {
4747
}
4848

4949
func TestApplicationOrgInterface(t *testing.T) {
50-
_ = configtxapi.SubInitializer(NewApplicationOrgConfig("id", nil))
50+
_ = configtxapi.Handler(NewApplicationOrgConfig("id", nil))
5151
}
5252

5353
func TestApplicationOrgDoubleBegin(t *testing.T) {
5454
m := NewApplicationOrgConfig("id", nil)
55-
m.BeginConfig()
56-
assert.Panics(t, m.BeginConfig, "Two begins back to back should have caused a panic")
55+
m.BeginConfig(nil)
56+
assert.Panics(t, func() { m.BeginConfig(nil) }, "Two begins back to back should have caused a panic")
5757
}
5858

5959
func TestApplicationOrgCommitWithoutBegin(t *testing.T) {
@@ -76,7 +76,7 @@ func TestApplicationOrgAnchorPeers(t *testing.T) {
7676
invalidMessage := makeInvalidConfigValue()
7777
validMessage := TemplateAnchorPeers("id", endVal)
7878
m := NewApplicationOrgConfig("id", nil)
79-
m.BeginConfig()
79+
m.BeginConfig(nil)
8080

8181
assert.Error(t, m.ProposeConfig(AnchorPeersKey, invalidMessage), "Should have failed on invalid message")
8282
assert.NoError(t, m.ProposeConfig(groupToKeyValue(validMessage)), "Should not have failed on invalid message")

common/configtx/handlers/application/sharedconfig.go

+11-21
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ limitations under the License.
1717
package application
1818

1919
import (
20-
"fmt"
21-
2220
"github.com/hyperledger/fabric/common/configtx/api"
2321
"github.com/hyperledger/fabric/common/configtx/handlers"
2422
"github.com/hyperledger/fabric/common/configtx/handlers/msp"
@@ -77,14 +75,24 @@ func NewSharedConfigImpl(mspConfig *msp.MSPConfigHandler) *SharedConfigImpl {
7775
}
7876

7977
// BeginConfig is used to start a new config proposal
80-
func (di *SharedConfigImpl) BeginConfig() {
78+
func (di *SharedConfigImpl) BeginConfig(groups []string) ([]api.Handler, error) {
8179
logger.Debugf("Beginning a possible new peer shared config")
8280
if di.pendingConfig != nil {
8381
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
8482
}
8583
di.pendingConfig = &sharedConfig{
8684
orgs: make(map[string]api.ApplicationOrgConfig),
8785
}
86+
orgHandlers := make([]api.Handler, len(groups))
87+
for i, group := range groups {
88+
org, ok := di.pendingConfig.orgs[group]
89+
if !ok {
90+
org = NewApplicationOrgConfig(group, di.mspConfig)
91+
di.pendingConfig.orgs[group] = org
92+
}
93+
orgHandlers[i] = org.(*ApplicationOrgConfig)
94+
}
95+
return orgHandlers, nil
8896
}
8997

9098
// RollbackConfig is used to abandon a new config proposal
@@ -113,21 +121,3 @@ func (di *SharedConfigImpl) ProposeConfig(key string, configValue *cb.ConfigValu
113121
func (di *SharedConfigImpl) Organizations() map[string]api.ApplicationOrgConfig {
114122
return di.config.orgs
115123
}
116-
117-
// Handler returns the associated api.Handler for the given path
118-
func (pm *SharedConfigImpl) Handler(path []string) (api.Handler, error) {
119-
if len(path) == 0 {
120-
return pm, nil
121-
}
122-
123-
if len(path) > 1 {
124-
return nil, fmt.Errorf("Application group allows only one further level of nesting")
125-
}
126-
127-
org, ok := pm.pendingConfig.orgs[path[0]]
128-
if !ok {
129-
org = NewApplicationOrgConfig(path[0], pm.mspConfig)
130-
pm.pendingConfig.orgs[path[0]] = org
131-
}
132-
return org.(*ApplicationOrgConfig), nil
133-
}

common/configtx/handlers/application/sharedconfig_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ func TestApplicationDoubleBegin(t *testing.T) {
4040
}()
4141

4242
m := NewSharedConfigImpl(nil)
43-
m.BeginConfig()
44-
m.BeginConfig()
43+
m.BeginConfig(nil)
44+
m.BeginConfig(nil)
4545
}
4646

4747
func TestApplicationCommitWithoutBegin(t *testing.T) {

common/configtx/handlers/channel/sharedconfig.go

+16-23
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,26 @@ func (pm *SharedConfigImpl) OrdererAddresses() []string {
106106
}
107107

108108
// BeginConfig is used to start a new config proposal
109-
func (pm *SharedConfigImpl) BeginConfig() {
109+
func (pm *SharedConfigImpl) BeginConfig(groups []string) ([]api.Handler, error) {
110+
handlers := make([]api.Handler, len(groups))
111+
112+
for i, group := range groups {
113+
switch group {
114+
case application.GroupKey:
115+
handlers[i] = pm.applicationConfig
116+
case orderer.GroupKey:
117+
handlers[i] = pm.ordererConfig
118+
default:
119+
return nil, fmt.Errorf("Disallowed channel group: %s", group)
120+
}
121+
}
122+
110123
if pm.pendingConfig != nil {
111124
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
112125
}
126+
113127
pm.pendingConfig = &chainConfig{}
128+
return handlers, nil
114129
}
115130

116131
// RollbackConfig is used to abandon a new config proposal
@@ -163,25 +178,3 @@ func (pm *SharedConfigImpl) ProposeConfig(key string, configValue *cb.ConfigValu
163178
}
164179
return nil
165180
}
166-
167-
// Handler returns the associated api.Handler for the given path
168-
func (pm *SharedConfigImpl) Handler(path []string) (api.Handler, error) {
169-
if len(path) == 0 {
170-
return pm, nil
171-
}
172-
173-
var initializer api.SubInitializer
174-
175-
switch path[0] {
176-
case application.GroupKey:
177-
initializer = pm.applicationConfig
178-
case orderer.GroupKey:
179-
initializer = pm.ordererConfig
180-
default:
181-
return nil, fmt.Errorf("Disallowed channel group: %s", path[0])
182-
}
183-
184-
return initializer.Handler(path[1:])
185-
186-
return nil, fmt.Errorf("Unallowed group")
187-
}

common/configtx/handlers/channel/sharedconfig_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ func TestDoubleBegin(t *testing.T) {
5555
}()
5656

5757
m := NewSharedConfigImpl(nil, nil)
58-
m.BeginConfig()
59-
m.BeginConfig()
58+
m.BeginConfig(nil)
59+
m.BeginConfig(nil)
6060
}
6161

6262
func TestCommitWithoutBegin(t *testing.T) {
@@ -85,7 +85,7 @@ func TestHashingAlgorithm(t *testing.T) {
8585
validAlgorithm := DefaultHashingAlgorithm()
8686

8787
m := NewSharedConfigImpl(nil, nil)
88-
m.BeginConfig()
88+
m.BeginConfig(nil)
8989

9090
err := m.ProposeConfig(HashingAlgorithmKey, invalidMessage)
9191
if err == nil {
@@ -115,7 +115,7 @@ func TestBlockDataHashingStructure(t *testing.T) {
115115
validWidth := DefaultBlockDataHashingStructure()
116116

117117
m := NewSharedConfigImpl(nil, nil)
118-
m.BeginConfig()
118+
m.BeginConfig(nil)
119119

120120
err := m.ProposeConfig(BlockDataHashingStructureKey, invalidMessage)
121121
if err == nil {
@@ -143,7 +143,7 @@ func TestOrdererAddresses(t *testing.T) {
143143
invalidMessage := makeInvalidConfigValue()
144144
validMessage := DefaultOrdererAddresses()
145145
m := NewSharedConfigImpl(nil, nil)
146-
m.BeginConfig()
146+
m.BeginConfig(nil)
147147

148148
err := m.ProposeConfig(OrdererAddressesKey, invalidMessage)
149149
if err == nil {

common/configtx/handlers/msp/config.go

-10
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"reflect"
2222

2323
"github.com/golang/protobuf/proto"
24-
"github.com/hyperledger/fabric/common/configtx/api"
2524
"github.com/hyperledger/fabric/msp"
2625
"github.com/hyperledger/fabric/protos/common"
2726
mspprotos "github.com/hyperledger/fabric/protos/msp"
@@ -83,12 +82,3 @@ func (bh *MSPConfigHandler) ProposeConfig(key string, configValue *common.Config
8382
bh.proposedMgr = msp.NewMSPManager()
8483
return bh.proposedMgr.Setup(bh.config)
8584
}
86-
87-
// Handler returns the associated api.Handler for the given path
88-
func (bh *MSPConfigHandler) Handler(path []string) (api.Handler, error) {
89-
if len(path) > 0 {
90-
return nil, fmt.Errorf("MSP handler does not support nested groups")
91-
}
92-
93-
return bh, nil
94-
}

common/configtx/handlers/orderer/sharedconfig.go

+13-21
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,24 @@ func (pm *ManagerImpl) EgressPolicyNames() []string {
157157
}
158158

159159
// BeginConfig is used to start a new config proposal
160-
func (pm *ManagerImpl) BeginConfig() {
161-
logger.Debugf("Beginning possible new orderer config")
160+
func (pm *ManagerImpl) BeginConfig(groups []string) ([]api.Handler, error) {
161+
logger.Debugf("Beginning a possible new orderer shared config")
162162
if pm.pendingConfig != nil {
163-
logger.Fatalf("Programming error, cannot call begin in the middle of a proposal")
163+
logger.Panicf("Programming error, cannot call begin in the middle of a proposal")
164164
}
165165
pm.pendingConfig = &ordererConfig{
166166
orgs: make(map[string]*handlers.OrgConfig),
167167
}
168+
orgHandlers := make([]api.Handler, len(groups))
169+
for i, group := range groups {
170+
org, ok := pm.pendingConfig.orgs[group]
171+
if !ok {
172+
org = handlers.NewOrgConfig(group, pm.mspConfig)
173+
pm.pendingConfig.orgs[group] = org
174+
}
175+
orgHandlers[i] = org
176+
}
177+
return orgHandlers, nil
168178
}
169179

170180
// RollbackConfig is used to abandon a new config proposal
@@ -275,24 +285,6 @@ func (pm *ManagerImpl) ProposeConfig(key string, configValue *cb.ConfigValue) er
275285
return nil
276286
}
277287

278-
// Handler returns the associated api.Handler for the given path
279-
func (pm *ManagerImpl) Handler(path []string) (api.Handler, error) {
280-
if len(path) == 0 {
281-
return pm, nil
282-
}
283-
284-
if len(path) > 1 {
285-
return nil, fmt.Errorf("Orderer group allows only one further level of nesting")
286-
}
287-
288-
org, ok := pm.pendingConfig.orgs[path[0]]
289-
if !ok {
290-
org = handlers.NewOrgConfig(path[0], pm.mspConfig)
291-
pm.pendingConfig.orgs[path[0]] = org
292-
}
293-
return org, nil
294-
}
295-
296288
// This does just a barebones sanity check.
297289
func brokerEntrySeemsValid(broker string) bool {
298290
if !strings.Contains(broker, ":") {

0 commit comments

Comments
 (0)