Skip to content

Commit e4b91f5

Browse files
C0rWinyacovm
authored andcommitted
[FAB-4327] Don't let peer to crash
Currently peer panics and dies while receiving genesis of the ordering service, there is no way to recover after such a failure (even after restarting the peer). This commit takes care to check block type before trying to create a channel. Change-Id: Ia72c3e6cccff0632b81f1334fb87841a2aecdab9 Signed-off-by: Artem Barger <[email protected]>
1 parent 7253ae5 commit e4b91f5

File tree

3 files changed

+89
-31
lines changed

3 files changed

+89
-31
lines changed

core/scc/cscc/configure.go

+57-31
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"fmt"
2727

2828
"github.com/golang/protobuf/proto"
29+
"github.com/hyperledger/fabric/common/config"
2930
"github.com/hyperledger/fabric/common/flogging"
3031
"github.com/hyperledger/fabric/common/policies"
3132
"github.com/hyperledger/fabric/core/chaincode/shim"
@@ -104,19 +105,33 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
104105

105106
switch fname {
106107
case JoinChain:
108+
if args[1] == nil {
109+
return shim.Error("Cannot join the channel <nil> configuration block provided")
110+
}
111+
112+
block, err := utils.GetBlockFromBlockBytes(args[1])
113+
if err != nil {
114+
return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
115+
}
116+
117+
cid, err := utils.GetChainIDFromBlock(block)
118+
if err != nil {
119+
return shim.Error(fmt.Sprintf("\"JoinChain\" request failed to extract "+
120+
"channel id from the block due to [%s]", err))
121+
}
122+
123+
if err := validateConfigBlock(block); err != nil {
124+
return shim.Error(fmt.Sprintf("\"JoinChain\" for chainID = %s failed because of validation "+
125+
"of configuration block, because of %s", cid, err))
126+
}
127+
107128
// 2. check local MSP Admins policy
108129
if err = e.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil {
109-
cid, e := utils.GetChainIDFromBlockBytes(args[1])
110-
errorString := fmt.Sprintf("\"JoinChain\" request failed authorization check "+
111-
"for channel [%s]: [%s]", cid, err)
112-
if e != nil {
113-
errorString = fmt.Sprintf("\"JoinChain\" request failed authorization [%s] and unable "+
114-
"to extract channel id from the block due to [%s]", err, e)
115-
}
116-
return shim.Error(errorString)
130+
return shim.Error(fmt.Sprintf("\"JoinChain\" request failed authorization check "+
131+
"for channel [%s]: [%s]", cid, err))
117132
}
118133

119-
return joinChain(args[1])
134+
return joinChain(cid, block)
120135
case GetConfigBlock:
121136
// 2. check the channel reader policy
122137
if err = e.policyChecker.CheckPolicy(string(args[1]), policies.ChannelApplicationReaders, sp); err != nil {
@@ -135,44 +150,55 @@ func (e *PeerConfiger) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
135150
return shim.Error(fmt.Sprintf("Requested function %s not found.", fname))
136151
}
137152

138-
// joinChain will join the specified chain in the configuration block.
139-
// Since it is the first block, it is the genesis block containing configuration
140-
// for this chain, so we want to update the Chain object with this info
141-
func joinChain(blockBytes []byte) pb.Response {
142-
block, err := extractBlock(blockBytes)
153+
// validateConfigBlock validate configuration block to see whenever it's contains valid config transaction
154+
func validateConfigBlock(block *common.Block) error {
155+
envelopeConfig, err := utils.ExtractEnvelope(block, 0)
143156
if err != nil {
144-
return shim.Error(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
157+
return errors.New(fmt.Sprintf("Failed to %s", err))
145158
}
146159

147-
if err = peer.CreateChainFromBlock(block); err != nil {
148-
return shim.Error(err.Error())
160+
configEnv := &common.ConfigEnvelope{}
161+
_, err = utils.UnmarshalEnvelopeOfType(envelopeConfig, common.HeaderType_CONFIG, configEnv)
162+
if err != nil {
163+
return errors.New(fmt.Sprintf("Bad configuration envelope: %s", err))
149164
}
150165

151-
chainID, err := utils.GetChainIDFromBlock(block)
152-
if err != nil {
153-
return shim.Error(fmt.Sprintf("Failed to get the chain ID from the configuration block, %s", err))
166+
if configEnv.Config == nil {
167+
return errors.New("Nil config envelope Config")
154168
}
155169

156-
peer.InitChain(chainID)
170+
if configEnv.Config.ChannelGroup == nil {
171+
return errors.New("Nil channel group")
172+
}
157173

158-
if err := producer.SendProducerBlockEvent(block); err != nil {
159-
cnflogger.Errorf("Error sending block event %s", err)
174+
if configEnv.Config.ChannelGroup.Groups == nil {
175+
return errors.New("No channel configuration groups are available")
160176
}
161177

162-
return shim.Success(nil)
178+
_, exists := configEnv.Config.ChannelGroup.Groups[config.ApplicationGroupKey]
179+
if !exists {
180+
return errors.New(fmt.Sprintf("Invalid configuration block, missing %s "+
181+
"configuration group", config.ApplicationGroupKey))
182+
}
183+
184+
return nil
163185
}
164186

165-
func extractBlock(bytes []byte) (*common.Block, error) {
166-
if bytes == nil {
167-
return nil, errors.New("Genesis block must not be nil.")
187+
// joinChain will join the specified chain in the configuration block.
188+
// Since it is the first block, it is the genesis block containing configuration
189+
// for this chain, so we want to update the Chain object with this info
190+
func joinChain(chainID string, block *common.Block) pb.Response {
191+
if err := peer.CreateChainFromBlock(block); err != nil {
192+
return shim.Error(err.Error())
168193
}
169194

170-
block, err := utils.GetBlockFromBlockBytes(bytes)
171-
if err != nil {
172-
return nil, errors.New(fmt.Sprintf("Failed to reconstruct the genesis block, %s", err))
195+
peer.InitChain(chainID)
196+
197+
if err := producer.SendProducerBlockEvent(block); err != nil {
198+
cnflogger.Errorf("Error sending block event %s", err)
173199
}
174200

175-
return block, nil
201+
return shim.Success(nil)
176202
}
177203

178204
// Return the current configuration block for the specified chainID. If the

core/scc/cscc/configure_test.go

+28
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/golang/protobuf/proto"
2626
configtxtest "github.com/hyperledger/fabric/common/configtx/test"
27+
"github.com/hyperledger/fabric/common/genesis"
2728
"github.com/hyperledger/fabric/common/localmsp"
2829
"github.com/hyperledger/fabric/common/mocks/scc"
2930
"github.com/hyperledger/fabric/common/policies"
@@ -274,6 +275,33 @@ func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) {
274275
}
275276
}
276277

278+
func TestPeerConfiger_SubmittingOrdererGenesis(t *testing.T) {
279+
viper.Set("peer.fileSystemPath", "/tmp/hyperledgertest/")
280+
os.Mkdir("/tmp/hyperledgertest", 0755)
281+
defer os.RemoveAll("/tmp/hyperledgertest/")
282+
283+
e := new(PeerConfiger)
284+
stub := shim.NewMockStub("PeerConfiger", e)
285+
286+
if res := stub.MockInit("1", nil); res.Status != shim.OK {
287+
fmt.Println("Init failed", string(res.Message))
288+
t.FailNow()
289+
}
290+
291+
block, err := genesis.NewFactoryImpl(configtxtest.OrdererTemplate()).Block("testChainID")
292+
assert.NoError(t, err)
293+
blockBytes := utils.MarshalOrPanic(block)
294+
295+
// Failed path: wrong parameter type
296+
args := [][]byte{[]byte("JoinChain"), []byte(blockBytes)}
297+
if res := stub.MockInvoke("2", args); res.Status == shim.OK {
298+
t.Fatalf("cscc invoke JoinChain should have failed with wrong genesis block. args: %v", args)
299+
} else {
300+
assert.Contains(t, res.Message, "missing Application configuration group")
301+
}
302+
303+
}
304+
277305
func mockConfigBlock() []byte {
278306
var blockBytes []byte = nil
279307
block, err := configtxtest.MakeGenesisBlock("mytestchainid")

protos/utils/commonutils.go

+4
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ func IsConfigBlock(block *cb.Block) bool {
275275
return false
276276
}
277277

278+
if payload.Header == nil {
279+
return false
280+
}
281+
278282
hdr, err := UnmarshalChannelHeader(payload.Header.ChannelHeader)
279283
if err != nil {
280284
return false

0 commit comments

Comments
 (0)