Skip to content

Commit d0c97c0

Browse files
author
Jason Yellick
committed
[FAB-5649] Invert configtx resource encapsulation
The configtx manager current retains a reference to the channel config, but to support other config types, this actually needs to be inverted so that the channel config retains a reference to the configtx manager. This CR performs this inversion and fixes the embedding packages of the configtx.Manager to instead embed the channelconfig.Resources. [FAB-5650] Move channel creation from configtx One of the last big offenders for putting channel config specific code into the configtx package is the templating code, which provides mechanisms to create new channel configurations. The generic templating is fine to remain there, but the channel specifics must be moved ot the channel config folder. Note: These two sub-tasks were squashed into one because of otherwise difficult to break import cycles. Change-Id: Ib8bf829216e19fbbbd8841c9a3551356ed1676b6 Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
1 parent 6e6b77d commit d0c97c0

File tree

33 files changed

+523
-450
lines changed

33 files changed

+523
-450
lines changed

common/config/channel/api.go

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
/*
2-
Copyright IBM Corp. 2017 All Rights Reserved.
2+
Copyright IBM Corp. All Rights Reserved.
33
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
4+
SPDX-License-Identifier: Apache-2.0
155
*/
166

17-
// Note, the directory is still configvalues, but this is stuttery and config
18-
// is a more accurate and better name, TODO, update directory
197
package config
208

219
import (
2210
"time"
2311

12+
configtxapi "github.com/hyperledger/fabric/common/configtx/api"
13+
"github.com/hyperledger/fabric/common/policies"
14+
"github.com/hyperledger/fabric/msp"
2415
cb "github.com/hyperledger/fabric/protos/common"
2516
ab "github.com/hyperledger/fabric/protos/orderer"
2617
pb "github.com/hyperledger/fabric/protos/peer"
@@ -97,3 +88,32 @@ type Orderer interface {
9788
// Organizations returns the organizations for the ordering service
9889
Organizations() map[string]Org
9990
}
91+
92+
// Resources is the common set of config resources for all channels
93+
// Depending on whether chain is used at the orderer or at the peer, other
94+
// config resources may be available
95+
type Resources interface {
96+
// ConfigtxManager returns the configtx.Manager for the channel
97+
ConfigtxManager() configtxapi.Manager
98+
99+
// PolicyManager returns the policies.Manager for the channel
100+
PolicyManager() policies.Manager
101+
102+
// ChannelConfig returns the config.Channel for the chain
103+
ChannelConfig() Channel
104+
105+
// OrdererConfig returns the config.Orderer for the channel
106+
// and whether the Orderer config exists
107+
OrdererConfig() (Orderer, bool)
108+
109+
// ConsortiumsConfig() returns the config.Consortiums for the channel
110+
// and whether the consortiums config exists
111+
ConsortiumsConfig() (Consortiums, bool)
112+
113+
// ApplicationConfig returns the configtxapplication.SharedConfig for the channel
114+
// and whether the Application config exists
115+
ApplicationConfig() (Application, bool)
116+
117+
// MSPManager returns the msp.MSPManager for the chain
118+
MSPManager() msp.MSPManager
119+
}

common/config/channel/initializer.go

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222
"github.com/hyperledger/fabric/common/cauthdsl"
2323
"github.com/hyperledger/fabric/common/config"
2424
configtxmsp "github.com/hyperledger/fabric/common/config/channel/msp"
25+
"github.com/hyperledger/fabric/common/configtx"
26+
configtxapi "github.com/hyperledger/fabric/common/configtx/api"
2527
"github.com/hyperledger/fabric/common/policies"
2628
"github.com/hyperledger/fabric/msp"
2729
cb "github.com/hyperledger/fabric/protos/common"
@@ -35,13 +37,19 @@ type resources struct {
3537
policyManager *policies.ManagerImpl
3638
configRoot *Root
3739
mspConfigHandler *configtxmsp.MSPConfigHandler
40+
configtxManager configtxapi.Manager
3841
}
3942

4043
// PolicyManager returns the policies.Manager for the chain
4144
func (r *resources) PolicyManager() policies.Manager {
4245
return r.policyManager
4346
}
4447

48+
// ConfigtxManager returns the configtxapi.Manager for the chain
49+
func (r *resources) ConfigtxManager() configtxapi.Manager {
50+
return r.configtxManager
51+
}
52+
4553
// ChannelConfig returns the api.ChannelConfig for the chain
4654
func (r *resources) ChannelConfig() Channel {
4755
return r.configRoot.Channel()
@@ -133,18 +141,45 @@ func (i *policyProposerRoot) CommitProposals(tx interface{}) {}
133141

134142
type Initializer struct {
135143
*resources
144+
configtxapi.Manager
136145
ppr *policyProposerRoot
137146
}
138147

139-
// NewInitializer creates a chain Initializer for the basic set of common chain resources
140-
func NewInitializer() *Initializer {
148+
// New creates a new channel config, complete with backing configtx manager
149+
// TODO move configtx.Manager to resources, make func on Resources type
150+
func New(envConfig *cb.Envelope, callOnUpdate []func(*Initializer)) (*Initializer, error) {
141151
resources := newResources()
142-
return &Initializer{
152+
i := &Initializer{
143153
resources: resources,
144154
ppr: &policyProposerRoot{
145155
policyManager: resources.policyManager,
146156
},
147157
}
158+
var err error
159+
initialized := false
160+
i.Manager, err = configtx.NewManagerImpl(envConfig, i, []func(cm configtxapi.Manager){
161+
func(cm configtxapi.Manager) {
162+
// This gets invoked once at instantiation before we are ready for it
163+
// we manually do this right after
164+
if !initialized {
165+
return
166+
}
167+
logger.Criticalf("Making callback normally")
168+
for _, callback := range callOnUpdate {
169+
callback(i)
170+
}
171+
},
172+
})
173+
if err != nil {
174+
return nil, err
175+
}
176+
initialized = true
177+
i.resources.configtxManager = i.Manager
178+
logger.Criticalf("Making callback manually")
179+
for _, callback := range callOnUpdate {
180+
callback(i)
181+
}
182+
return i, err
148183
}
149184

150185
func (i *Initializer) RootGroupKey() string {

common/config/channel/template.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package config
8+
9+
import (
10+
"fmt"
11+
12+
configmsp "github.com/hyperledger/fabric/common/config/channel/msp"
13+
"github.com/hyperledger/fabric/common/configtx"
14+
"github.com/hyperledger/fabric/common/policies"
15+
"github.com/hyperledger/fabric/common/util"
16+
"github.com/hyperledger/fabric/msp"
17+
cb "github.com/hyperledger/fabric/protos/common"
18+
"github.com/hyperledger/fabric/protos/utils"
19+
)
20+
21+
const (
22+
msgVersion = int32(0)
23+
epoch = 0
24+
)
25+
26+
type channelCreationTemplate struct {
27+
consortiumName string
28+
orgs []string
29+
}
30+
31+
// NewChainCreationTemplate takes a consortium name and a Template to produce a
32+
// Template which outputs an appropriately constructed list of ConfigUpdateEnvelopes.
33+
func NewChainCreationTemplate(consortiumName string, orgs []string) configtx.Template {
34+
return &channelCreationTemplate{
35+
consortiumName: consortiumName,
36+
orgs: orgs,
37+
}
38+
}
39+
40+
func (cct *channelCreationTemplate) Envelope(channelID string) (*cb.ConfigUpdateEnvelope, error) {
41+
rSet := TemplateConsortium(cct.consortiumName)
42+
wSet := TemplateConsortium(cct.consortiumName)
43+
44+
rSet.Groups[ApplicationGroupKey] = cb.NewConfigGroup()
45+
wSet.Groups[ApplicationGroupKey] = cb.NewConfigGroup()
46+
47+
for _, org := range cct.orgs {
48+
rSet.Groups[ApplicationGroupKey].Groups[org] = cb.NewConfigGroup()
49+
wSet.Groups[ApplicationGroupKey].Groups[org] = cb.NewConfigGroup()
50+
}
51+
52+
wSet.Groups[ApplicationGroupKey].ModPolicy = configmsp.AdminsPolicyKey
53+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.AdminsPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.AdminsPolicyKey, cb.ImplicitMetaPolicy_MAJORITY)
54+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.AdminsPolicyKey].ModPolicy = configmsp.AdminsPolicyKey
55+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.WritersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.WritersPolicyKey, cb.ImplicitMetaPolicy_ANY)
56+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.WritersPolicyKey].ModPolicy = configmsp.AdminsPolicyKey
57+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.ReadersPolicyKey] = policies.ImplicitMetaPolicyWithSubPolicy(configmsp.ReadersPolicyKey, cb.ImplicitMetaPolicy_ANY)
58+
wSet.Groups[ApplicationGroupKey].Policies[configmsp.ReadersPolicyKey].ModPolicy = configmsp.AdminsPolicyKey
59+
wSet.Groups[ApplicationGroupKey].Version = 1
60+
61+
return &cb.ConfigUpdateEnvelope{
62+
ConfigUpdate: utils.MarshalOrPanic(&cb.ConfigUpdate{
63+
ChannelId: channelID,
64+
ReadSet: rSet,
65+
WriteSet: wSet,
66+
}),
67+
}, nil
68+
}
69+
70+
// MakeChainCreationTransaction is a handy utility function for creating new chain transactions using the underlying Template framework
71+
func MakeChainCreationTransaction(channelID string, consortium string, signer msp.SigningIdentity, orgs ...string) (*cb.Envelope, error) {
72+
newChainTemplate := NewChainCreationTemplate(consortium, orgs)
73+
newConfigUpdateEnv, err := newChainTemplate.Envelope(channelID)
74+
if err != nil {
75+
return nil, err
76+
}
77+
78+
payloadSignatureHeader := &cb.SignatureHeader{}
79+
if signer != nil {
80+
sSigner, err := signer.Serialize()
81+
if err != nil {
82+
return nil, fmt.Errorf("Serialization of identity failed, err %s", err)
83+
}
84+
85+
newConfigUpdateEnv.Signatures = []*cb.ConfigSignature{&cb.ConfigSignature{
86+
SignatureHeader: utils.MarshalOrPanic(utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())),
87+
}}
88+
89+
newConfigUpdateEnv.Signatures[0].Signature, err = signer.Sign(util.ConcatenateBytes(newConfigUpdateEnv.Signatures[0].SignatureHeader, newConfigUpdateEnv.ConfigUpdate))
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
payloadSignatureHeader = utils.MakeSignatureHeader(sSigner, utils.CreateNonceOrPanic())
95+
}
96+
97+
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, msgVersion, channelID, epoch)
98+
utils.SetTxID(payloadChannelHeader, payloadSignatureHeader)
99+
payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader)
100+
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(newConfigUpdateEnv)}
101+
paylBytes := utils.MarshalOrPanic(payload)
102+
103+
var sig []byte
104+
if signer != nil {
105+
// sign the payload
106+
sig, err = signer.Sign(paylBytes)
107+
if err != nil {
108+
return nil, err
109+
}
110+
}
111+
112+
return &cb.Envelope{Payload: paylBytes, Signature: sig}, nil
113+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package config
8+
9+
import (
10+
"testing"
11+
12+
configmsp "github.com/hyperledger/fabric/common/config/channel/msp"
13+
"github.com/hyperledger/fabric/common/configtx"
14+
mmsp "github.com/hyperledger/fabric/common/mocks/msp"
15+
cb "github.com/hyperledger/fabric/protos/common"
16+
"github.com/hyperledger/fabric/protos/utils"
17+
18+
"github.com/golang/protobuf/proto"
19+
"github.com/stretchr/testify/assert"
20+
)
21+
22+
func TestNewChainTemplate(t *testing.T) {
23+
consortiumName := "Test"
24+
orgs := []string{"org1", "org2", "org3"}
25+
nct := NewChainCreationTemplate(consortiumName, orgs)
26+
27+
newChainID := "foo"
28+
configEnv, err := nct.Envelope(newChainID)
29+
if err != nil {
30+
t.Fatalf("Error creation a chain creation config")
31+
}
32+
33+
configUpdate, err := configtx.UnmarshalConfigUpdate(configEnv.ConfigUpdate)
34+
if err != nil {
35+
t.Fatalf("Should not have errored: %s", err)
36+
}
37+
38+
consortiumProto := &cb.Consortium{}
39+
err = proto.Unmarshal(configUpdate.WriteSet.Values[ConsortiumKey].Value, consortiumProto)
40+
assert.NoError(t, err)
41+
assert.Equal(t, consortiumName, consortiumProto.Name, "Should have set correct consortium name")
42+
43+
assert.Equal(t, configUpdate.WriteSet.Groups[ApplicationGroupKey].Version, uint64(1))
44+
45+
assert.Len(t, configUpdate.WriteSet.Groups[ApplicationGroupKey].Groups, len(orgs))
46+
47+
for _, org := range orgs {
48+
group, ok := configUpdate.WriteSet.Groups[ApplicationGroupKey].Groups[org]
49+
assert.True(t, ok, "Expected to find %s but did not", org)
50+
for _, policy := range group.Policies {
51+
assert.Equal(t, configmsp.AdminsPolicyKey, policy.ModPolicy)
52+
}
53+
}
54+
}
55+
56+
func TestMakeChainCreationTransactionWithSigner(t *testing.T) {
57+
channelID := "foo"
58+
59+
signer, err := mmsp.NewNoopMsp().GetDefaultSigningIdentity()
60+
assert.NoError(t, err, "Creating noop MSP")
61+
62+
cct, err := MakeChainCreationTransaction(channelID, "test", signer)
63+
assert.NoError(t, err, "Making chain creation tx")
64+
65+
assert.NotEmpty(t, cct.Signature, "Should have signature")
66+
67+
payload, err := utils.UnmarshalPayload(cct.Payload)
68+
assert.NoError(t, err, "Unmarshaling payload")
69+
70+
configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
71+
assert.NoError(t, err, "Unmarshaling ConfigUpdateEnvelope")
72+
73+
assert.NotEmpty(t, configUpdateEnv.Signatures, "Should have config env sigs")
74+
75+
sigHeader, err := utils.GetSignatureHeader(payload.Header.SignatureHeader)
76+
assert.NoError(t, err, "Unmarshaling SignatureHeader")
77+
assert.NotEmpty(t, sigHeader.Creator, "Creator specified")
78+
}
79+
80+
func TestMakeChainCreationTransactionNoSigner(t *testing.T) {
81+
channelID := "foo"
82+
cct, err := MakeChainCreationTransaction(channelID, "test", nil)
83+
assert.NoError(t, err, "Making chain creation tx")
84+
85+
assert.Empty(t, cct.Signature, "Should have empty signature")
86+
87+
payload, err := utils.UnmarshalPayload(cct.Payload)
88+
assert.NoError(t, err, "Unmarshaling payload")
89+
90+
configUpdateEnv, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
91+
assert.NoError(t, err, "Unmarshaling ConfigUpdateEnvelope")
92+
93+
assert.Empty(t, configUpdateEnv.Signatures, "Should have no config env sigs")
94+
95+
sigHeader, err := utils.GetSignatureHeader(payload.Header.SignatureHeader)
96+
assert.NoError(t, err, "Unmarshaling SignatureHeader")
97+
assert.Empty(t, sigHeader.Creator, "No creator specified")
98+
}

0 commit comments

Comments
 (0)