Skip to content

Commit 54dc537

Browse files
author
Jason Yellick
committed
[FAB-2612] Enable configtxgen configtx inspection
https://jira.hyperledger.org/browse/FAB-2612 FAB-2584 enabled the configtxgen tool to dump the configuration from a config block. This CR extends that functionality to the configtx for channel creation as well. Change-Id: Ie9136016200d136bfbb7126b5ff97a70018d4c95 Signed-off-by: Jason Yellick <[email protected]>
1 parent d4a11db commit 54dc537

File tree

3 files changed

+162
-22
lines changed

3 files changed

+162
-22
lines changed

common/configtx/tool/configtxgen/main.go

+91-20
Original file line numberDiff line numberDiff line change
@@ -37,79 +37,81 @@ import (
3737

3838
var logger = logging.MustGetLogger("common/configtx/tool")
3939

40-
func doOutputBlock(pgen provisional.Generator, channelID string, outputBlock string) {
40+
func doOutputBlock(pgen provisional.Generator, channelID string, outputBlock string) error {
4141
logger.Info("Generating genesis block")
4242
genesisBlock := pgen.GenesisBlockForChannel(channelID)
4343
logger.Info("Writing genesis block")
4444
err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644)
4545
if err != nil {
46-
logger.Errorf("Error writing genesis block: %s", err)
46+
return fmt.Errorf("Error writing genesis block: %s", err)
4747
}
48+
return nil
4849
}
4950

50-
func doOutputChannelCreateTx(pgen provisional.Generator, channelID string, outputChannelCreateTx string) {
51+
func doOutputChannelCreateTx(pgen provisional.Generator, channelID string, outputChannelCreateTx string) error {
5152
logger.Info("Generating new channel configtx")
5253
// TODO, use actual MSP eventually
5354
signer, err := msp.NewNoopMsp().GetDefaultSigningIdentity()
5455
if err != nil {
55-
logger.Fatalf("Error getting signing identity: %s", err)
56+
return fmt.Errorf("Error getting signing identity: %s", err)
5657
}
5758
configtx, err := configtx.MakeChainCreationTransaction(provisional.AcceptAllPolicyKey, channelID, signer, pgen.ChannelTemplate())
5859
if err != nil {
59-
logger.Fatalf("Error generating configtx: %s", err)
60+
return fmt.Errorf("Error generating configtx: %s", err)
6061
}
6162
logger.Info("Writing new channel tx")
6263
err = ioutil.WriteFile(outputChannelCreateTx, utils.MarshalOrPanic(configtx), 0644)
6364
if err != nil {
64-
logger.Errorf("Error writing channel create tx: %s", err)
65+
return fmt.Errorf("Error writing channel create tx: %s", err)
6566
}
67+
return nil
6668
}
6769

68-
func doInspectBlock(inspectBlock string) {
70+
func doInspectBlock(inspectBlock string) error {
6971
logger.Info("Inspecting block")
7072
data, err := ioutil.ReadFile(inspectBlock)
7173
logger.Info("Parsing genesis block")
7274
block := &cb.Block{}
7375
err = proto.Unmarshal(data, block)
7476
if err != nil {
75-
logger.Fatalf("Error unmarshaling block: %s", err)
77+
fmt.Errorf("Error unmarshaling block: %s", err)
7678
}
7779

7880
ctx, err := utils.ExtractEnvelope(block, 0)
7981
if err != nil {
80-
logger.Fatalf("Error retrieving configtx from block: %s", err)
82+
return fmt.Errorf("Error retrieving configtx from block: %s", err)
8183
}
8284

8385
payload, err := utils.UnmarshalPayload(ctx.Payload)
8486
if err != nil {
85-
logger.Fatalf("Error extracting configtx payload: %s", err)
87+
return fmt.Errorf("Error extracting configtx payload: %s", err)
8688
}
8789

8890
if payload.Header == nil {
89-
logger.Fatalf("Config block did not contain header")
91+
return fmt.Errorf("Config block did not contain header")
9092
}
9193

9294
header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
9395
if err != nil {
94-
logger.Fatalf("Error unmarshaling channel header: %s", err)
96+
return fmt.Errorf("Error unmarshaling channel header: %s", err)
9597
}
9698

9799
if header.Type != int32(cb.HeaderType_CONFIG) {
98-
logger.Fatalf("Bad header type: %d", header.Type)
100+
return fmt.Errorf("Bad header type: %d", header.Type)
99101
}
100102

101103
configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
102104
if err != nil {
103-
logger.Fatalf("Bad configuration envelope")
105+
return fmt.Errorf("Bad configuration envelope")
104106
}
105107

106108
if configEnvelope.Config == nil {
107-
logger.Fatalf("ConfigEnvelope contained no config")
109+
return fmt.Errorf("ConfigEnvelope contained no config")
108110
}
109111

110112
configResult, err := configtx.NewConfigResult(configEnvelope.Config.ChannelGroup, configtx.NewInitializer())
111113
if err != nil {
112-
logger.Fatalf("Error parsing configuration: %s", err)
114+
return fmt.Errorf("Error parsing configuration: %s", err)
113115
}
114116

115117
buffer := &bytes.Buffer{}
@@ -118,16 +120,73 @@ func doInspectBlock(inspectBlock string) {
118120
fmt.Printf("Config for channel: %s at sequence %d\n", header.ChannelId, configEnvelope.Config.Sequence)
119121

120122
fmt.Println(buffer.String())
123+
return nil
124+
}
125+
126+
func doInspectChannelCreateTx(inspectChannelCreateTx string) error {
127+
logger.Info("Inspecting transaction")
128+
data, err := ioutil.ReadFile(inspectChannelCreateTx)
129+
logger.Info("Parsing transaction")
130+
env, err := utils.UnmarshalEnvelope(data)
131+
if err != nil {
132+
return fmt.Errorf("Error unmarshaling envelope: %s", err)
133+
}
134+
135+
payload, err := utils.UnmarshalPayload(env.Payload)
136+
if err != nil {
137+
return fmt.Errorf("Error extracting configtx payload: %s", err)
138+
}
139+
140+
if payload.Header == nil {
141+
return fmt.Errorf("Config block did not contain header")
142+
}
143+
144+
header, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
145+
if err != nil {
146+
return fmt.Errorf("Error unmarshaling channel header: %s", err)
147+
}
148+
149+
if header.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
150+
return fmt.Errorf("Bad header type: %d", header.Type)
151+
}
152+
153+
configUpdateEnvelope, err := configtx.UnmarshalConfigUpdateEnvelope(payload.Data)
154+
if err != nil {
155+
return fmt.Errorf("Bad ConfigUpdateEnvelope")
156+
}
157+
158+
configUpdate, err := configtx.UnmarshalConfigUpdate(configUpdateEnvelope.ConfigUpdate)
159+
if err != nil {
160+
return fmt.Errorf("ConfigUpdateEnvelope contained no config")
161+
}
162+
163+
if configUpdate.ChannelId != header.ChannelId {
164+
return fmt.Errorf("ConfigUpdateEnvelope was for different channel than envelope: %s vs %s", configUpdate.ChannelId, header.ChannelId)
165+
}
166+
167+
configResult, err := configtx.NewConfigResult(configUpdate.WriteSet, configtx.NewInitializer())
168+
if err != nil {
169+
return fmt.Errorf("Error parsing configuration: %s", err)
170+
}
171+
172+
buffer := &bytes.Buffer{}
173+
json.Indent(buffer, []byte(configResult.JSON()), "", " ")
174+
175+
fmt.Printf("Config for channel: %s\n", header.ChannelId)
176+
177+
fmt.Println(buffer.String())
178+
return nil
121179
}
122180

123181
func main() {
124-
var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock string
182+
var outputBlock, outputChannelCreateTx, profile, channelID, inspectBlock, inspectChannelCreateTx string
125183

126184
flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)")
127185
flag.StringVar(&channelID, "channelID", provisional.TestChainID, "The channel ID to use in the configtx")
128186
flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)")
129187
flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureProfile, "The profile from configtx.yaml to use for generation.")
130188
flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path")
189+
flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path")
131190

132191
flag.Parse()
133192

@@ -139,15 +198,27 @@ func main() {
139198
pgen := provisional.New(config)
140199

141200
if outputBlock != "" {
142-
doOutputBlock(pgen, channelID, outputBlock)
201+
if err := doOutputBlock(pgen, channelID, outputBlock); err != nil {
202+
logger.Fatalf("Error on outputBlock: %s", err)
203+
}
143204
}
144205

145206
if outputChannelCreateTx != "" {
146-
doOutputChannelCreateTx(pgen, channelID, outputChannelCreateTx)
207+
if err := doOutputChannelCreateTx(pgen, channelID, outputChannelCreateTx); err != nil {
208+
logger.Fatalf("Error on outputChannelCreateTx: %s", err)
209+
}
147210
}
148211

149212
if inspectBlock != "" {
150-
doInspectBlock(inspectBlock)
213+
if err := doInspectBlock(inspectBlock); err != nil {
214+
logger.Fatalf("Error on inspectBlock: %s", err)
215+
}
216+
}
217+
218+
if inspectChannelCreateTx != "" {
219+
if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil {
220+
logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
221+
}
151222
}
152223

153224
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
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.
15+
*/
16+
17+
package main
18+
19+
import (
20+
"io/ioutil"
21+
"os"
22+
"testing"
23+
24+
"github.com/hyperledger/fabric/bccsp/factory"
25+
genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
26+
"github.com/hyperledger/fabric/common/configtx/tool/provisional"
27+
28+
"github.com/stretchr/testify/assert"
29+
)
30+
31+
var tmpDir string
32+
33+
func TestMain(m *testing.M) {
34+
dir, err := ioutil.TempDir("", "configtxgen")
35+
if err != nil {
36+
panic("Error creating temp dir")
37+
}
38+
tmpDir = dir
39+
testResult := m.Run()
40+
os.RemoveAll(dir)
41+
42+
os.Exit(testResult)
43+
}
44+
45+
func TestInspectBlock(t *testing.T) {
46+
blockDest := tmpDir + string(os.PathSeparator) + "block"
47+
48+
factory.InitFactories(nil)
49+
config := genesisconfig.Load(genesisconfig.SampleInsecureProfile)
50+
pgen := provisional.New(config)
51+
52+
assert.NoError(t, doOutputBlock(pgen, "foo", blockDest), "Good block generation request")
53+
assert.NoError(t, doInspectBlock(blockDest), "Good block inspection request")
54+
}
55+
56+
func TestInspectConfigTx(t *testing.T) {
57+
configTxDest := tmpDir + string(os.PathSeparator) + "configtx"
58+
59+
factory.InitFactories(nil)
60+
config := genesisconfig.Load(genesisconfig.SampleInsecureProfile)
61+
pgen := provisional.New(config)
62+
63+
assert.NoError(t, doOutputChannelCreateTx(pgen, "foo", configTxDest), "Good outputChannelCreateTx generation request")
64+
assert.NoError(t, doInspectChannelCreateTx(configTxDest), "Good configtx inspection request")
65+
}

docs/configtxgen.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ configtxgen -profile <profile_name> -outputCreateChannelTx <output.txname>
3939

4040
This will output a marshaled `Envelope` message which may be sent to broadcast to create a channel.
4141

42-
## Reviewing a configuration block
42+
## Reviewing a configuration
4343

44-
In addition to creating configuration, the `configtxgen` tool is also capable of inspecting configuration. You may even wish to combine the inspection with generation. For example:
44+
In addition to creating configuration, the `configtxgen` tool is also capable of inspecting configuration.
45+
46+
It supports inspecting both configuration blocks, and configuration transactions. You may use the inspect flags `-inspectBlock` and `-inspectChannelCreateTx` respectively with the path to a file to inspect to output a human readable (JSON) representation of the configuration.
47+
48+
You may even wish to combine the inspection with generation. For example:
4549

4650
```
4751
$ build/bin/configtxgen -channelID foo -outputBlock foo.block -inspectBlock foo.block

0 commit comments

Comments
 (0)