github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/orderer/multichain/systemchain_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 multichain 18 19 import ( 20 "bytes" 21 "fmt" 22 "testing" 23 24 "github.com/hyperledger/fabric/common/config" 25 "github.com/hyperledger/fabric/common/configtx" 26 configtxapi "github.com/hyperledger/fabric/common/configtx/api" 27 mockconfig "github.com/hyperledger/fabric/common/mocks/config" 28 mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx" 29 "github.com/hyperledger/fabric/orderer/common/filter" 30 cb "github.com/hyperledger/fabric/protos/common" 31 "github.com/hyperledger/fabric/protos/utils" 32 logging "github.com/op/go-logging" 33 34 "github.com/stretchr/testify/assert" 35 ) 36 37 type mockSupport struct { 38 msc *mockconfig.Orderer 39 } 40 41 func newMockSupport() *mockSupport { 42 return &mockSupport{ 43 msc: &mockconfig.Orderer{}, 44 } 45 } 46 47 func (ms *mockSupport) SharedConfig() config.Orderer { 48 return ms.msc 49 } 50 51 type mockChainCreator struct { 52 ms *mockSupport 53 newChains []*cb.Envelope 54 NewChannelConfigErr error 55 } 56 57 func newMockChainCreator() *mockChainCreator { 58 mcc := &mockChainCreator{ 59 ms: newMockSupport(), 60 } 61 return mcc 62 } 63 64 func (mcc *mockChainCreator) newChain(configTx *cb.Envelope) { 65 mcc.newChains = append(mcc.newChains, configTx) 66 } 67 68 func (mcc *mockChainCreator) channelsCount() int { 69 return len(mcc.newChains) 70 } 71 72 func (mcc *mockChainCreator) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) { 73 if mcc.NewChannelConfigErr != nil { 74 return nil, mcc.NewChannelConfigErr 75 } 76 confUpdate := configtx.UnmarshalConfigUpdateOrPanic(configtx.UnmarshalConfigUpdateEnvelopeOrPanic(utils.UnmarshalPayloadOrPanic(envConfigUpdate.Payload).Data).ConfigUpdate) 77 return &mockconfigtx.Manager{ 78 ConfigEnvelopeVal: &cb.ConfigEnvelope{ 79 Config: &cb.Config{Sequence: 1, ChannelGroup: confUpdate.WriteSet}, 80 LastUpdate: envConfigUpdate, 81 }, 82 }, nil 83 } 84 85 func TestGoodProposal(t *testing.T) { 86 newChainID := "new-chain-id" 87 88 mcc := newMockChainCreator() 89 90 configEnv, err := configtx.NewCompositeTemplate( 91 configtx.NewSimpleTemplate( 92 config.DefaultHashingAlgorithm(), 93 config.DefaultBlockDataHashingStructure(), 94 config.TemplateOrdererAddresses([]string{"foo"}), 95 ), 96 configtx.NewChainCreationTemplate("SampleConsortium", []string{}), 97 ).Envelope(newChainID) 98 assert.Nil(t, err, "Error constructing configtx") 99 100 ingressTx := makeConfigTxFromConfigUpdateEnvelope(newChainID, configEnv) 101 wrapped := wrapConfigTx(ingressTx) 102 103 sysFilter := newSystemChainFilter(mcc.ms, mcc) 104 action, committer := sysFilter.Apply(wrapped) 105 106 assert.EqualValues(t, action, filter.Accept, "Did not accept valid transaction") 107 assert.True(t, committer.Isolated(), "Channel creation belong in its own block") 108 109 committer.Commit() 110 assert.Len(t, mcc.newChains, 1, "Proposal should only have created 1 new chain") 111 112 assert.Equal(t, ingressTx, mcc.newChains[0], "New chain should have been created with ingressTx") 113 } 114 115 func TestProposalRejectedByConfig(t *testing.T) { 116 newChainID := "NewChainID" 117 118 mcc := newMockChainCreator() 119 mcc.NewChannelConfigErr = fmt.Errorf("Error creating channel") 120 121 configEnv, err := configtx.NewCompositeTemplate( 122 configtx.NewSimpleTemplate( 123 config.DefaultHashingAlgorithm(), 124 config.DefaultBlockDataHashingStructure(), 125 config.TemplateOrdererAddresses([]string{"foo"}), 126 ), 127 configtx.NewChainCreationTemplate("SampleConsortium", []string{}), 128 ).Envelope(newChainID) 129 if err != nil { 130 t.Fatalf("Error constructing configtx") 131 } 132 ingressTx := makeConfigTxFromConfigUpdateEnvelope(newChainID, configEnv) 133 wrapped := wrapConfigTx(ingressTx) 134 135 sysFilter := newSystemChainFilter(mcc.ms, mcc) 136 action, _ := sysFilter.Apply(wrapped) 137 138 assert.EqualValues(t, action, filter.Reject, "Did not accept valid transaction") 139 assert.Len(t, mcc.newChains, 0, "Proposal should not have created a new chain") 140 } 141 142 func TestNumChainsExceeded(t *testing.T) { 143 newChainID := "NewChainID" 144 145 mcc := newMockChainCreator() 146 mcc.ms.msc.MaxChannelsCountVal = 1 147 mcc.newChains = make([]*cb.Envelope, 2) 148 149 configEnv, err := configtx.NewCompositeTemplate( 150 configtx.NewSimpleTemplate( 151 config.DefaultHashingAlgorithm(), 152 config.DefaultBlockDataHashingStructure(), 153 config.TemplateOrdererAddresses([]string{"foo"}), 154 ), 155 configtx.NewChainCreationTemplate("SampleConsortium", []string{}), 156 ).Envelope(newChainID) 157 if err != nil { 158 t.Fatalf("Error constructing configtx") 159 } 160 ingressTx := makeConfigTxFromConfigUpdateEnvelope(newChainID, configEnv) 161 wrapped := wrapConfigTx(ingressTx) 162 163 sysFilter := newSystemChainFilter(mcc.ms, mcc) 164 action, _ := sysFilter.Apply(wrapped) 165 166 assert.EqualValues(t, filter.Reject, action, "Transaction had created too many channels") 167 } 168 169 func TestBadProposal(t *testing.T) { 170 mcc := newMockChainCreator() 171 sysFilter := newSystemChainFilter(mcc.ms, mcc) 172 // logging.SetLevel(logging.DEBUG, "orderer/multichain") 173 t.Run("BadPayload", func(t *testing.T) { 174 action, committer := sysFilter.Apply(&cb.Envelope{Payload: []byte("bad payload")}) 175 assert.EqualValues(t, action, filter.Forward, "Should of skipped invalid tx") 176 assert.Nil(t, committer) 177 }) 178 179 // set logger to logger with a backend that writes to a byte buffer 180 var buffer bytes.Buffer 181 logger.SetBackend(logging.AddModuleLevel(logging.NewLogBackend(&buffer, "", 0))) 182 // reset the logger after test 183 defer func() { 184 logger = logging.MustGetLogger("orderer/multichain") 185 }() 186 187 for _, tc := range []struct { 188 name string 189 payload *cb.Payload 190 action filter.Action 191 regexp string 192 }{ 193 { 194 "MissingPayloadHeader", 195 &cb.Payload{}, 196 filter.Forward, 197 "", 198 }, 199 { 200 "BadChannelHeader", 201 &cb.Payload{ 202 Header: &cb.Header{ 203 ChannelHeader: []byte("bad channel header"), 204 }, 205 }, 206 filter.Forward, 207 "", 208 }, 209 { 210 "BadConfigTx", 211 &cb.Payload{ 212 Header: &cb.Header{ 213 ChannelHeader: utils.MarshalOrPanic( 214 &cb.ChannelHeader{ 215 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 216 }, 217 ), 218 }, 219 Data: []byte("bad configTx"), 220 }, 221 filter.Reject, 222 "", 223 }, 224 { 225 "BadConfigTxPayload", 226 &cb.Payload{ 227 Header: &cb.Header{ 228 ChannelHeader: utils.MarshalOrPanic( 229 &cb.ChannelHeader{ 230 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 231 }, 232 ), 233 }, 234 Data: utils.MarshalOrPanic( 235 &cb.Envelope{ 236 Payload: []byte("bad payload"), 237 }, 238 ), 239 }, 240 filter.Reject, 241 "Error unmarshaling envelope payload", 242 }, 243 { 244 "MissingConfigTxChannelHeader", 245 &cb.Payload{ 246 Header: &cb.Header{ 247 ChannelHeader: utils.MarshalOrPanic( 248 &cb.ChannelHeader{ 249 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 250 }, 251 ), 252 }, 253 Data: utils.MarshalOrPanic( 254 &cb.Envelope{ 255 Payload: utils.MarshalOrPanic( 256 &cb.Payload{}, 257 ), 258 }, 259 ), 260 }, 261 filter.Reject, 262 "Not a config transaction", 263 }, 264 { 265 "BadConfigTxChannelHeader", 266 &cb.Payload{ 267 Header: &cb.Header{ 268 ChannelHeader: utils.MarshalOrPanic( 269 &cb.ChannelHeader{ 270 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 271 }, 272 ), 273 }, 274 Data: utils.MarshalOrPanic( 275 &cb.Envelope{ 276 Payload: utils.MarshalOrPanic( 277 &cb.Payload{ 278 Header: &cb.Header{ 279 ChannelHeader: []byte("bad channel header"), 280 }, 281 }, 282 ), 283 }, 284 ), 285 }, 286 filter.Reject, 287 "Error unmarshaling channel header", 288 }, 289 { 290 "BadConfigTxChannelHeaderType", 291 &cb.Payload{ 292 Header: &cb.Header{ 293 ChannelHeader: utils.MarshalOrPanic( 294 &cb.ChannelHeader{ 295 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 296 }, 297 ), 298 }, 299 Data: utils.MarshalOrPanic( 300 &cb.Envelope{ 301 Payload: utils.MarshalOrPanic( 302 &cb.Payload{ 303 Header: &cb.Header{ 304 ChannelHeader: utils.MarshalOrPanic( 305 &cb.ChannelHeader{ 306 Type: 0xBad, 307 }, 308 ), 309 }, 310 }, 311 ), 312 }, 313 ), 314 }, 315 filter.Reject, 316 "Not a config transaction", 317 }, 318 { 319 "BadConfigEnvelope", 320 &cb.Payload{ 321 Header: &cb.Header{ 322 ChannelHeader: utils.MarshalOrPanic( 323 &cb.ChannelHeader{ 324 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 325 }, 326 ), 327 }, 328 Data: utils.MarshalOrPanic( 329 &cb.Envelope{ 330 Payload: utils.MarshalOrPanic( 331 &cb.Payload{ 332 Header: &cb.Header{ 333 ChannelHeader: utils.MarshalOrPanic( 334 &cb.ChannelHeader{ 335 Type: int32(cb.HeaderType_CONFIG), 336 }, 337 ), 338 }, 339 Data: []byte("bad config update"), 340 }, 341 ), 342 }, 343 ), 344 }, 345 filter.Reject, 346 "Error unmarshalling config envelope from payload", 347 }, 348 { 349 "MissingConfigEnvelopeLastUpdate", 350 &cb.Payload{ 351 Header: &cb.Header{ 352 ChannelHeader: utils.MarshalOrPanic( 353 &cb.ChannelHeader{ 354 Type: int32(cb.HeaderType_ORDERER_TRANSACTION), 355 }, 356 ), 357 }, 358 Data: utils.MarshalOrPanic( 359 &cb.Envelope{ 360 Payload: utils.MarshalOrPanic( 361 &cb.Payload{ 362 Header: &cb.Header{ 363 ChannelHeader: utils.MarshalOrPanic( 364 &cb.ChannelHeader{ 365 Type: int32(cb.HeaderType_CONFIG), 366 }, 367 ), 368 }, 369 Data: utils.MarshalOrPanic( 370 &cb.ConfigEnvelope{}, 371 ), 372 }, 373 ), 374 }, 375 ), 376 }, 377 filter.Reject, 378 "Must include a config update", 379 }, 380 } { 381 t.Run(tc.name, func(t *testing.T) { 382 buffer.Reset() 383 action, committer := sysFilter.Apply(&cb.Envelope{Payload: utils.MarshalOrPanic(tc.payload)}) 384 assert.EqualValues(t, tc.action, action, "Expected tx to be %sed, but instead the tx will be %sed.", filterActionToString(tc.action), filterActionToString(action)) 385 assert.Nil(t, committer) 386 assert.Regexp(t, tc.regexp, buffer.String()) 387 }) 388 } 389 } 390 391 func filterActionToString(action filter.Action) string { 392 switch action { 393 case filter.Accept: 394 return "accept" 395 case filter.Forward: 396 return "forward" 397 case filter.Reject: 398 return "reject" 399 default: 400 return "" 401 } 402 }