github.com/anjalikarhana/fabric@v2.1.1+incompatible/orderer/common/multichannel/registrar_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package multichannel 8 9 import ( 10 "io/ioutil" 11 "os" 12 "testing" 13 14 "github.com/golang/protobuf/proto" 15 cb "github.com/hyperledger/fabric-protos-go/common" 16 ab "github.com/hyperledger/fabric-protos-go/orderer" 17 "github.com/hyperledger/fabric/bccsp/sw" 18 "github.com/hyperledger/fabric/common/channelconfig" 19 "github.com/hyperledger/fabric/common/ledger/blockledger" 20 "github.com/hyperledger/fabric/common/ledger/blockledger/fileledger" 21 "github.com/hyperledger/fabric/common/metrics/disabled" 22 "github.com/hyperledger/fabric/common/policies" 23 "github.com/hyperledger/fabric/core/config/configtest" 24 "github.com/hyperledger/fabric/internal/configtxgen/encoder" 25 "github.com/hyperledger/fabric/internal/configtxgen/genesisconfig" 26 "github.com/hyperledger/fabric/internal/pkg/identity" 27 "github.com/hyperledger/fabric/orderer/common/blockcutter" 28 "github.com/hyperledger/fabric/orderer/common/localconfig" 29 "github.com/hyperledger/fabric/orderer/common/multichannel/mocks" 30 "github.com/hyperledger/fabric/orderer/consensus" 31 "github.com/hyperledger/fabric/protoutil" 32 "github.com/pkg/errors" 33 "github.com/stretchr/testify/assert" 34 "github.com/stretchr/testify/require" 35 ) 36 37 //go:generate counterfeiter -o mocks/resources.go --fake-name Resources . resources 38 39 type resources interface { 40 channelconfig.Resources 41 } 42 43 //go:generate counterfeiter -o mocks/orderer_config.go --fake-name OrdererConfig . ordererConfig 44 45 type ordererConfig interface { 46 channelconfig.Orderer 47 } 48 49 //go:generate counterfeiter -o mocks/orderer_capabilities.go --fake-name OrdererCapabilities . ordererCapabilities 50 51 type ordererCapabilities interface { 52 channelconfig.OrdererCapabilities 53 } 54 55 //go:generate counterfeiter -o mocks/channel_config.go --fake-name ChannelConfig . channelConfig 56 57 type channelConfig interface { 58 channelconfig.Channel 59 } 60 61 //go:generate counterfeiter -o mocks/channel_capabilities.go --fake-name ChannelCapabilities . channelCapabilities 62 63 type channelCapabilities interface { 64 channelconfig.ChannelCapabilities 65 } 66 67 //go:generate counterfeiter -o mocks/signer_serializer.go --fake-name SignerSerializer . signerSerializer 68 69 type signerSerializer interface { 70 identity.SignerSerializer 71 } 72 73 func mockCrypto() *mocks.SignerSerializer { 74 return &mocks.SignerSerializer{} 75 } 76 77 func newLedgerAndFactory(dir string, chainID string, genesisBlockSys *cb.Block) (blockledger.Factory, blockledger.ReadWriter) { 78 rlf, err := fileledger.New(dir, &disabled.Provider{}) 79 if err != nil { 80 panic(err) 81 } 82 83 rl, err := rlf.GetOrCreate(chainID) 84 if err != nil { 85 panic(err) 86 } 87 88 if genesisBlockSys != nil { 89 err = rl.Append(genesisBlockSys) 90 if err != nil { 91 panic(err) 92 } 93 } 94 return rlf, rl 95 } 96 97 func testMessageOrderAndRetrieval(maxMessageCount uint32, chainID string, chainSupport *ChainSupport, lr blockledger.ReadWriter, t *testing.T) { 98 messages := make([]*cb.Envelope, maxMessageCount) 99 for i := uint32(0); i < maxMessageCount; i++ { 100 messages[i] = makeNormalTx(chainID, int(i)) 101 } 102 for _, message := range messages { 103 chainSupport.Order(message, 0) 104 } 105 it, _ := lr.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 106 defer it.Close() 107 block, status := it.Next() 108 assert.Equal(t, cb.Status_SUCCESS, status, "Could not retrieve block") 109 for i := uint32(0); i < maxMessageCount; i++ { 110 assert.True(t, proto.Equal(messages[i], protoutil.ExtractEnvelopeOrPanic(block, int(i))), "Block contents wrong at index %d", i) 111 } 112 } 113 114 func TestConfigTx(t *testing.T) { 115 // system channel 116 confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 117 genesisBlockSys := encoder.New(confSys).GenesisBlock() 118 119 // Tests for a normal channel which contains 3 config transactions and other 120 // normal transactions to make sure the right one returned 121 t.Run("GetConfigTx - ok", func(t *testing.T) { 122 tmpdir, err := ioutil.TempDir("", "registrar_test-") 123 require.NoError(t, err) 124 defer os.RemoveAll(tmpdir) 125 126 _, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) 127 for i := 0; i < 5; i++ { 128 rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", i)})) 129 } 130 rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx("testchannelid", 5)})) 131 ctx := makeConfigTx("testchannelid", 6) 132 rl.Append(blockledger.CreateNextBlock(rl, []*cb.Envelope{ctx})) 133 134 // block with LAST_CONFIG metadata in SIGNATURES field 135 block := blockledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx("testchannelid", 7)}) 136 blockSignatureValue := protoutil.MarshalOrPanic(&cb.OrdererBlockMetadata{ 137 LastConfig: &cb.LastConfig{Index: 7}, 138 }) 139 block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] = protoutil.MarshalOrPanic(&cb.Metadata{Value: blockSignatureValue}) 140 rl.Append(block) 141 142 pctx := configTx(rl) 143 assert.True(t, proto.Equal(pctx, ctx), "Did not select most recent config transaction") 144 }) 145 } 146 147 func TestNewRegistrar(t *testing.T) { 148 //system channel 149 confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 150 genesisBlockSys := encoder.New(confSys).GenesisBlock() 151 152 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 153 assert.NoError(t, err) 154 155 // This test checks to make sure the orderer refuses to come up if it cannot find a system channel 156 t.Run("No system chain - failure", func(t *testing.T) { 157 tmpdir, err := ioutil.TempDir("", "registrar_test-") 158 require.NoError(t, err) 159 defer os.RemoveAll(tmpdir) 160 161 lf, err := fileledger.New(tmpdir, &disabled.Provider{}) 162 require.NoError(t, err) 163 164 consenters := make(map[string]consensus.Consenter) 165 consenters[confSys.Orderer.OrdererType] = &mockConsenter{} 166 167 assert.NotPanics(t, func() { 168 NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters) 169 }, "Should not panic when starting without a system channel") 170 }) 171 172 // This test checks to make sure that the orderer refuses to come up if there are multiple system channels 173 t.Run("Multiple system chains - failure", func(t *testing.T) { 174 tmpdir, err := ioutil.TempDir("", "registrar_test-") 175 require.NoError(t, err) 176 defer os.RemoveAll(tmpdir) 177 178 lf, err := fileledger.New(tmpdir, &disabled.Provider{}) 179 require.NoError(t, err) 180 181 for _, id := range []string{"foo", "bar"} { 182 rl, err := lf.GetOrCreate(id) 183 assert.NoError(t, err) 184 185 err = rl.Append(encoder.New(confSys).GenesisBlockForChannel(id)) 186 assert.NoError(t, err) 187 } 188 189 consenters := make(map[string]consensus.Consenter) 190 consenters[confSys.Orderer.OrdererType] = &mockConsenter{} 191 192 assert.Panics(t, func() { 193 NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider).Initialize(consenters) 194 }, "Two system channels should have caused panic") 195 }) 196 197 // This test essentially brings the entire system up and is ultimately what main.go will replicate 198 t.Run("Correct flow", func(t *testing.T) { 199 tmpdir, err := ioutil.TempDir("", "registrar_test-") 200 require.NoError(t, err) 201 defer os.RemoveAll(tmpdir) 202 203 lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) 204 205 consenters := make(map[string]consensus.Consenter) 206 consenters[confSys.Orderer.OrdererType] = &mockConsenter{} 207 208 manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider) 209 manager.Initialize(consenters) 210 211 chainSupport := manager.GetChain("Fake") 212 assert.Nilf(t, chainSupport, "Should not have found a chain that was not created") 213 214 chainSupport = manager.GetChain("testchannelid") 215 assert.NotNilf(t, chainSupport, "Should have gotten chain which was initialized by ledger") 216 217 testMessageOrderAndRetrieval(confSys.Orderer.BatchSize.MaxMessageCount, "testchannelid", chainSupport, rl, t) 218 }) 219 } 220 221 func TestCreateChain(t *testing.T) { 222 //system channel 223 confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 224 genesisBlockSys := encoder.New(confSys).GenesisBlock() 225 226 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 227 assert.NoError(t, err) 228 229 t.Run("Create chain", func(t *testing.T) { 230 tmpdir, err := ioutil.TempDir("", "registrar_test-") 231 require.NoError(t, err) 232 defer os.RemoveAll(tmpdir) 233 234 lf, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) 235 236 consenters := make(map[string]consensus.Consenter) 237 consenters[confSys.Orderer.OrdererType] = &mockConsenter{} 238 239 manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider) 240 manager.Initialize(consenters) 241 242 ledger, err := lf.GetOrCreate("mychannel") 243 assert.NoError(t, err) 244 245 genesisBlock := encoder.New(confSys).GenesisBlockForChannel("mychannel") 246 ledger.Append(genesisBlock) 247 248 // Before creating the chain, it doesn't exist 249 assert.Nil(t, manager.GetChain("mychannel")) 250 // After creating the chain, it exists 251 manager.CreateChain("mychannel") 252 chain := manager.GetChain("mychannel") 253 assert.NotNil(t, chain) 254 // A subsequent creation, replaces the chain. 255 manager.CreateChain("mychannel") 256 chain2 := manager.GetChain("mychannel") 257 assert.NotNil(t, chain2) 258 // They are not the same 259 assert.NotEqual(t, chain, chain2) 260 // The old chain is halted 261 _, ok := <-chain.Chain.(*mockChain).queue 262 assert.False(t, ok) 263 // The new chain is not halted: Close the channel to prove that. 264 close(chain2.Chain.(*mockChain).queue) 265 }) 266 267 // This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain 268 t.Run("New chain", func(t *testing.T) { 269 expectedLastConfigSeq := uint64(1) 270 newChainID := "test-new-chain" 271 272 tmpdir, err := ioutil.TempDir("", "registrar_test-") 273 require.NoError(t, err) 274 defer os.RemoveAll(tmpdir) 275 276 lf, rl := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) 277 278 consenters := make(map[string]consensus.Consenter) 279 consenters[confSys.Orderer.OrdererType] = &mockConsenter{} 280 281 manager := NewRegistrar(localconfig.TopLevel{}, lf, mockCrypto(), &disabled.Provider{}, cryptoProvider) 282 manager.Initialize(consenters) 283 orglessChannelConf := genesisconfig.Load(genesisconfig.SampleSingleMSPChannelProfile, configtest.GetDevConfigDir()) 284 orglessChannelConf.Application.Organizations = nil 285 envConfigUpdate, err := encoder.MakeChannelCreationTransaction(newChainID, mockCrypto(), orglessChannelConf) 286 assert.NoError(t, err, "Constructing chain creation tx") 287 288 res, err := manager.NewChannelConfig(envConfigUpdate) 289 assert.NoError(t, err, "Constructing initial channel config") 290 291 configEnv, err := res.ConfigtxValidator().ProposeConfigUpdate(envConfigUpdate) 292 assert.NoError(t, err, "Proposing initial update") 293 assert.Equal(t, expectedLastConfigSeq, configEnv.GetConfig().Sequence, "Sequence of config envelope for new channel should always be set to %d", expectedLastConfigSeq) 294 295 ingressTx, err := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch) 296 assert.NoError(t, err, "Creating ingresstx") 297 298 wrapped := wrapConfigTx(ingressTx) 299 300 chainSupport := manager.GetChain(manager.SystemChannelID()) 301 assert.NotNilf(t, chainSupport, "Could not find system channel") 302 303 chainSupport.Configure(wrapped, 0) 304 func() { 305 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 306 defer it.Close() 307 block, status := it.Next() 308 if status != cb.Status_SUCCESS { 309 t.Fatalf("Could not retrieve block") 310 } 311 if len(block.Data.Data) != 1 { 312 t.Fatalf("Should have had only one message in the orderer transaction block") 313 } 314 315 assert.True(t, proto.Equal(wrapped, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Orderer config block contains wrong transaction") 316 }() 317 318 chainSupport = manager.GetChain(newChainID) 319 if chainSupport == nil { 320 t.Fatalf("Should have gotten new chain which was created") 321 } 322 323 messages := make([]*cb.Envelope, confSys.Orderer.BatchSize.MaxMessageCount) 324 for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ { 325 messages[i] = makeNormalTx(newChainID, i) 326 } 327 328 for _, message := range messages { 329 chainSupport.Order(message, 0) 330 } 331 332 it, _ := chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}}) 333 defer it.Close() 334 block, status := it.Next() 335 if status != cb.Status_SUCCESS { 336 t.Fatalf("Could not retrieve new chain genesis block") 337 } 338 if len(block.Data.Data) != 1 { 339 t.Fatalf("Should have had only one message in the new genesis block") 340 } 341 342 assert.True(t, proto.Equal(ingressTx, protoutil.UnmarshalEnvelopeOrPanic(block.Data.Data[0])), "Genesis block contains wrong transaction") 343 344 block, status = it.Next() 345 if status != cb.Status_SUCCESS { 346 t.Fatalf("Could not retrieve block on new chain") 347 } 348 for i := 0; i < int(confSys.Orderer.BatchSize.MaxMessageCount); i++ { 349 if !proto.Equal(protoutil.ExtractEnvelopeOrPanic(block, i), messages[i]) { 350 t.Errorf("Block contents wrong at index %d in new chain", i) 351 } 352 } 353 354 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 355 assert.NoError(t, err) 356 rcs := newChainSupport(manager, chainSupport.ledgerResources, consenters, mockCrypto(), blockcutter.NewMetrics(&disabled.Provider{}), cryptoProvider) 357 assert.Equal(t, expectedLastConfigSeq, rcs.lastConfigSeq, "On restart, incorrect lastConfigSeq") 358 }) 359 } 360 361 func TestResourcesCheck(t *testing.T) { 362 mockOrderer := &mocks.OrdererConfig{} 363 mockOrdererCaps := &mocks.OrdererCapabilities{} 364 mockOrderer.CapabilitiesReturns(mockOrdererCaps) 365 mockChannel := &mocks.ChannelConfig{} 366 mockChannelCaps := &mocks.ChannelCapabilities{} 367 mockChannel.CapabilitiesReturns(mockChannelCaps) 368 369 mockResources := &mocks.Resources{} 370 mockResources.PolicyManagerReturns(&policies.ManagerImpl{}) 371 372 t.Run("GoodResources", func(t *testing.T) { 373 mockResources.OrdererConfigReturns(mockOrderer, true) 374 mockResources.ChannelConfigReturns(mockChannel) 375 376 err := checkResources(mockResources) 377 assert.NoError(t, err) 378 }) 379 380 t.Run("MissingOrdererConfigPanic", func(t *testing.T) { 381 mockResources.OrdererConfigReturns(nil, false) 382 383 err := checkResources(mockResources) 384 assert.Error(t, err) 385 assert.Regexp(t, "config does not contain orderer config", err.Error()) 386 }) 387 388 t.Run("MissingOrdererCapability", func(t *testing.T) { 389 mockResources.OrdererConfigReturns(mockOrderer, true) 390 mockOrdererCaps.SupportedReturns(errors.New("An error")) 391 392 err := checkResources(mockResources) 393 assert.Error(t, err) 394 assert.Regexp(t, "config requires unsupported orderer capabilities:", err.Error()) 395 396 // reset 397 mockOrdererCaps.SupportedReturns(nil) 398 }) 399 400 t.Run("MissingChannelCapability", func(t *testing.T) { 401 mockChannelCaps.SupportedReturns(errors.New("An error")) 402 403 err := checkResources(mockResources) 404 assert.Error(t, err) 405 assert.Regexp(t, "config requires unsupported channel capabilities:", err.Error()) 406 }) 407 408 t.Run("MissingOrdererConfigPanic", func(t *testing.T) { 409 mockResources.OrdererConfigReturns(nil, false) 410 411 assert.Panics(t, func() { 412 checkResourcesOrPanic(mockResources) 413 }) 414 }) 415 } 416 417 // The registrar's BroadcastChannelSupport implementation should reject message types which should not be processed directly. 418 func TestBroadcastChannelSupport(t *testing.T) { 419 // system channel 420 confSys := genesisconfig.Load(genesisconfig.SampleInsecureSoloProfile, configtest.GetDevConfigDir()) 421 genesisBlockSys := encoder.New(confSys).GenesisBlock() 422 423 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 424 assert.NoError(t, err) 425 426 t.Run("Rejection", func(t *testing.T) { 427 tmpdir, err := ioutil.TempDir("", "registrar_test-") 428 require.NoError(t, err) 429 defer os.RemoveAll(tmpdir) 430 431 ledgerFactory, _ := newLedgerAndFactory(tmpdir, "testchannelid", genesisBlockSys) 432 mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}} 433 registrar := NewRegistrar(localconfig.TopLevel{}, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider) 434 registrar.Initialize(mockConsenters) 435 randomValue := 1 436 configTx := makeConfigTx("testchannelid", randomValue) 437 _, _, _, err = registrar.BroadcastChannelSupport(configTx) 438 assert.Error(t, err, "Messages of type HeaderType_CONFIG should return an error.") 439 }) 440 441 t.Run("No system channel", func(t *testing.T) { 442 tmpdir, err := ioutil.TempDir("", "registrar_test-") 443 require.NoError(t, err) 444 defer os.RemoveAll(tmpdir) 445 446 ledgerFactory, _ := newLedgerAndFactory(tmpdir, "", nil) 447 mockConsenters := map[string]consensus.Consenter{confSys.Orderer.OrdererType: &mockConsenter{}} 448 config := localconfig.TopLevel{} 449 config.General.BootstrapMethod = "none" 450 config.General.GenesisFile = "" 451 registrar := NewRegistrar(config, ledgerFactory, mockCrypto(), &disabled.Provider{}, cryptoProvider) 452 registrar.Initialize(mockConsenters) 453 configTx := makeConfigTxFull("testchannelid", 1) 454 _, _, _, err = registrar.BroadcastChannelSupport(configTx) 455 assert.Error(t, err) 456 assert.Equal(t, "channel creation request not allowed because the orderer system channel is not yet defined", err.Error()) 457 }) 458 }