Skip to content

Commit 6ac2f0e

Browse files
Jason Yellickkchristidis
Jason Yellick
authored andcommitted
[FAB-2821] Print readset/writeset/deltaset on updt
The configtxgen tool currently only prints the organizations in the channel creation configtx. This is not enough information for an admin to decide whether to sign or not. This CR makes the configtx printing much verbose, including the read set, write set, and computes the delta set for easy identification of non-overlap between the read and write sets. Change-Id: I3f9bfc2839ec595b1f2fc9a0cb149797ed4f862b Signed-off-by: Jason Yellick <[email protected]> Signed-off-by: Kostas Christidis <[email protected]>
1 parent 3fb58c8 commit 6ac2f0e

File tree

8 files changed

+84
-40
lines changed

8 files changed

+84
-40
lines changed

common/configtx/config.go

+16-9
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func NewConfigResult(config *cb.ConfigGroup, proposer api.Proposer) (ConfigResul
4040
type configResult struct {
4141
tx interface{}
4242
groupName string
43+
groupKey string
4344
group *cb.ConfigGroup
4445
valueHandler config.ValueProposer
4546
policyHandler policies.Proposer
@@ -51,7 +52,7 @@ type configResult struct {
5152
func (cr *configResult) JSON() string {
5253
var buffer bytes.Buffer
5354
buffer.WriteString("{")
54-
cr.bufferJSON(&buffer)
55+
cr.subResults[0].bufferJSON(&buffer)
5556
buffer.WriteString("}")
5657
return buffer.String()
5758

@@ -70,7 +71,7 @@ func (cr *configResult) bufferJSON(buffer *bytes.Buffer) {
7071

7172
// "GroupName": {
7273
buffer.WriteString("\"")
73-
buffer.WriteString(cr.groupName)
74+
buffer.WriteString(cr.groupKey)
7475
buffer.WriteString("\": {")
7576

7677
// "Values": {
@@ -229,6 +230,7 @@ func proposeGroup(result *configResult) error {
229230
for i, subGroup := range subGroups {
230231
result.subResults = append(result.subResults, &configResult{
231232
tx: result.tx,
233+
groupKey: subGroup,
232234
groupName: result.groupName + "/" + subGroup,
233235
group: result.group.Groups[subGroup],
234236
valueHandler: subValueHandlers[i],
@@ -243,12 +245,6 @@ func proposeGroup(result *configResult) error {
243245
}
244246
}
245247

246-
err = result.preCommit()
247-
if err != nil {
248-
result.rollback()
249-
return err
250-
}
251-
252248
return nil
253249
}
254250

@@ -271,5 +267,16 @@ func processConfig(channelGroup *cb.ConfigGroup, proposer api.Proposer) (*config
271267

272268
func (cm *configManager) processConfig(channelGroup *cb.ConfigGroup) (*configResult, error) {
273269
logger.Debugf("Beginning new config for channel %s", cm.current.channelID)
274-
return processConfig(channelGroup, cm.initializer)
270+
configResult, err := processConfig(channelGroup, cm.initializer)
271+
if err != nil {
272+
return nil, err
273+
}
274+
275+
err = configResult.preCommit()
276+
if err != nil {
277+
configResult.rollback()
278+
return nil, err
279+
}
280+
281+
return configResult, nil
275282
}

common/configtx/config_test.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ import (
3131

3232
func TestJSON(t *testing.T) {
3333
cr := &configResult{
34-
groupName: "rootGroup",
34+
groupKey: "rootGroup",
3535
group: &cb.ConfigGroup{
3636
Values: map[string]*cb.ConfigValue{
3737
"outer": &cb.ConfigValue{Version: 1, ModPolicy: "mod1"},
3838
},
3939
},
4040
subResults: []*configResult{
4141
&configResult{
42-
groupName: "innerGroup1",
42+
groupKey: "innerGroup1",
4343
group: &cb.ConfigGroup{
4444
Values: map[string]*cb.ConfigValue{
4545
"inner1": &cb.ConfigValue{ModPolicy: "mod3"},
@@ -56,7 +56,7 @@ func TestJSON(t *testing.T) {
5656
},
5757
},
5858
&configResult{
59-
groupName: "innerGroup2",
59+
groupKey: "innerGroup2",
6060
group: &cb.ConfigGroup{
6161
Values: map[string]*cb.ConfigValue{
6262
"inner2": &cb.ConfigValue{ModPolicy: "mod3"},
@@ -78,8 +78,10 @@ func TestJSON(t *testing.T) {
7878
},
7979
}
8080

81+
crWrapper := &configResult{subResults: []*configResult{cr}}
82+
8183
buffer := &bytes.Buffer{}
82-
assert.NoError(t, json.Indent(buffer, []byte(cr.JSON()), "", ""), "JSON should parse nicely")
84+
assert.NoError(t, json.Indent(buffer, []byte(crWrapper.JSON()), "", ""), "JSON should parse nicely")
8385

8486
expected := "{\"rootGroup\":{\"Values\":{\"outer\":{\"Version\":\"1\",\"ModPolicy\":\"mod1\",\"Value\":{\"type\":\"outer\"}}},\"Policies\":{},\"Groups\":{\"innerGroup1\":{\"Values\":{\"inner1\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner1\"}}},\"Policies\":{\"policy1\":{\"Version\":\"0\",\"ModPolicy\":\"mod1\",\"Policy\":{\"PolicyType\":\"0\",\"Policy\":{\"type\":\"policy1\"}}}},\"Groups\":{}},\"innerGroup2\":{\"Values\":{\"inner2\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner2\"}}},\"Policies\":{\"policy2\":{\"Version\":\"0\",\"ModPolicy\":\"mod2\",\"Policy\":{\"PolicyType\":\"1\",\"Policy\":{\"type\":\"policy2\"}}}},\"Groups\":{}}}}}"
8587

common/configtx/configmap.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ const (
3333
PathSeparator = "/"
3434
)
3535

36-
// mapConfig is intended to be called outside this file
36+
// MapConfig is intended to be called outside this file
3737
// it takes a ConfigGroup and generates a map of fqPath to comparables (or error on invalid keys)
38-
func mapConfig(channelGroup *cb.ConfigGroup) (map[string]comparable, error) {
38+
func MapConfig(channelGroup *cb.ConfigGroup) (map[string]comparable, error) {
3939
result := make(map[string]comparable)
4040
if channelGroup != nil {
4141
err := recurseConfig(result, []string{RootGroupKey}, channelGroup)
@@ -46,7 +46,7 @@ func mapConfig(channelGroup *cb.ConfigGroup) (map[string]comparable, error) {
4646
return result, nil
4747
}
4848

49-
// addToMap is used only internally by mapConfig
49+
// addToMap is used only internally by MapConfig
5050
func addToMap(cg comparable, result map[string]comparable) error {
5151
var fqPath string
5252

@@ -77,7 +77,7 @@ func addToMap(cg comparable, result map[string]comparable) error {
7777
return nil
7878
}
7979

80-
// recurseConfig is used only internally by mapConfig
80+
// recurseConfig is used only internally by MapConfig
8181
func recurseConfig(result map[string]comparable, path []string, group *cb.ConfigGroup) error {
8282
if err := addToMap(comparable{key: path[len(path)-1], path: path[:len(path)-1], ConfigGroup: group}, result); err != nil {
8383
return err

common/configtx/configmap_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func TestConfigMap(t *testing.T) {
3838
config.Groups["0DeepGroup"].Groups["1DeepGroup"] = cb.NewConfigGroup()
3939
config.Groups["0DeepGroup"].Groups["1DeepGroup"].Values["2DeepValue"] = &cb.ConfigValue{}
4040

41-
confMap, err := mapConfig(config)
41+
confMap, err := MapConfig(config)
4242
assert.NoError(t, err, "Should not have errored building map")
4343

4444
assert.Len(t, confMap, 7, "There should be 7 entries in the config map")
@@ -68,7 +68,7 @@ func TestMapConfigBack(t *testing.T) {
6868
config.Groups["0DeepGroup"].Groups["1DeepGroup"] = cb.NewConfigGroup()
6969
config.Groups["0DeepGroup"].Groups["1DeepGroup"].Values["2DeepValue"] = &cb.ConfigValue{}
7070

71-
confMap, err := mapConfig(config)
71+
confMap, err := MapConfig(config)
7272
assert.NoError(t, err, "Should not have errored building map")
7373

7474
newConfig, err := configMapToConfig(confMap)

common/configtx/manager.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func NewManagerImpl(envConfig *cb.Envelope, initializer api.Initializer, callOnU
102102
return nil, fmt.Errorf("Bad channel id: %s", err)
103103
}
104104

105-
configMap, err := mapConfig(configEnv.Config.ChannelGroup)
105+
configMap, err := MapConfig(configEnv.Config.ChannelGroup)
106106
if err != nil {
107107
return nil, fmt.Errorf("Error converting config to map: %s", err)
108108
}

common/configtx/tool/configtxgen/main.go

+50-15
Original file line numberDiff line numberDiff line change
@@ -195,21 +195,29 @@ func doInspectBlock(inspectBlock string) error {
195195
return fmt.Errorf("ConfigEnvelope contained no config")
196196
}
197197

198-
configResult, err := configtx.NewConfigResult(configEnvelope.Config.ChannelGroup, configtx.NewInitializer())
198+
configAsJSON, err := configGroupAsJSON(configEnvelope.Config.ChannelGroup)
199199
if err != nil {
200-
return fmt.Errorf("Error parsing configuration: %s", err)
200+
return err
201+
}
202+
203+
fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
204+
fmt.Println(configAsJSON)
205+
206+
return nil
207+
}
208+
209+
func configGroupAsJSON(group *cb.ConfigGroup) (string, error) {
210+
configResult, err := configtx.NewConfigResult(group, configtx.NewInitializer())
211+
if err != nil {
212+
return "", fmt.Errorf("Error parsing config: %s", err)
201213
}
202214

203215
buffer := &bytes.Buffer{}
204216
err = json.Indent(buffer, []byte(configResult.JSON()), "", " ")
205217
if err != nil {
206-
return fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
218+
return "", fmt.Errorf("Error in output JSON (usually a programming bug): %s", err)
207219
}
208-
209-
fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
210-
211-
fmt.Println(buffer.String())
212-
return nil
220+
return buffer.String(), nil
213221
}
214222

215223
func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
@@ -253,21 +261,48 @@ func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
253261
return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId)
254262
}
255263

264+
fmt.Printf("\nChannel creation for channel: %s\n", header.ChannelId)
265+
fmt.Println()
266+
267+
if configUpdate.ReadSet == nil {
268+
fmt.Println("Read Set: empty")
269+
} else {
270+
fmt.Println("Read Set:")
271+
readSetAsJSON, err := configGroupAsJSON(configUpdate.ReadSet)
272+
if err != nil {
273+
return err
274+
}
275+
fmt.Println(readSetAsJSON)
276+
}
277+
fmt.Println()
278+
256279
if configUpdate.WriteSet == nil {
257280
return fmt.Errorf("Empty WriteSet")
258281
}
259282

260-
if configUpdate.WriteSet.Groups[config.ApplicationGroupKey] == nil {
261-
return fmt.Errorf("Empty Application group")
283+
fmt.Println("Write Set:")
284+
writeSetAsJSON, err := configGroupAsJSON(configUpdate.WriteSet)
285+
if err != nil {
286+
return err
262287
}
288+
fmt.Println(writeSetAsJSON)
289+
fmt.Println()
263290

264-
var orgs []string
265-
266-
for name := range configUpdate.WriteSet.Groups[config.ApplicationGroupKey].Groups {
267-
orgs = append(orgs, name)
291+
readSetMap, err := configtx.MapConfig(configUpdate.ReadSet)
292+
if err != nil {
293+
return fmt.Errorf("Error mapping read set: %s", err)
294+
}
295+
writeSetMap, err := configtx.MapConfig(configUpdate.WriteSet)
296+
if err != nil {
297+
return fmt.Errorf("Error mapping write set: %s", err)
268298
}
269299

270-
fmt.Printf("\nChannel creation for channel: %s with orgs %v\n\n", header.ChannelId, orgs)
300+
fmt.Println("Delta Set:")
301+
deltaSet := configtx.ComputeDeltaSet(readSetMap, writeSetMap)
302+
for key := range deltaSet {
303+
fmt.Println(key)
304+
}
305+
fmt.Println()
271306

272307
return nil
273308
}

common/configtx/update.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func (c *configSet) verifyReadSet(readSet map[string]comparable) error {
3838
return nil
3939
}
4040

41-
func computeDeltaSet(readSet, writeSet map[string]comparable) map[string]comparable {
41+
func ComputeDeltaSet(readSet, writeSet map[string]comparable) map[string]comparable {
4242
result := make(map[string]comparable)
4343
for key, value := range writeSet {
4444
readVal, ok := readSet[key]
@@ -107,7 +107,7 @@ func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelop
107107
return nil, fmt.Errorf("Update not for correct channel: %s for %s", configUpdate.ChannelId, cm.current.channelID)
108108
}
109109

110-
readSet, err := mapConfig(configUpdate.ReadSet)
110+
readSet, err := MapConfig(configUpdate.ReadSet)
111111
if err != nil {
112112
return nil, fmt.Errorf("Error mapping ReadSet: %s", err)
113113
}
@@ -116,12 +116,12 @@ func (cm *configManager) authorizeUpdate(configUpdateEnv *cb.ConfigUpdateEnvelop
116116
return nil, fmt.Errorf("Error validating ReadSet: %s", err)
117117
}
118118

119-
writeSet, err := mapConfig(configUpdate.WriteSet)
119+
writeSet, err := MapConfig(configUpdate.WriteSet)
120120
if err != nil {
121121
return nil, fmt.Errorf("Error mapping WriteSet: %s", err)
122122
}
123123

124-
deltaSet := computeDeltaSet(readSet, writeSet)
124+
deltaSet := ComputeDeltaSet(readSet, writeSet)
125125
signedData, err := configUpdateEnv.AsSignedData()
126126
if err != nil {
127127
return nil, err

common/configtx/update_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestComputeDeltaSet(t *testing.T) {
6666
writeSet["2"] = comparable{ConfigValue: &cb.ConfigValue{Version: 1}}
6767
writeSet["3"] = comparable{}
6868

69-
result := computeDeltaSet(readSet, writeSet)
69+
result := ComputeDeltaSet(readSet, writeSet)
7070
assert.Len(t, result, 2, "Should have two values in the delta set")
7171
assert.NotNil(t, result["2"], "Element had version increased")
7272
assert.NotNil(t, result["3"], "Element was new")

0 commit comments

Comments
 (0)