github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/orderer/multichain/manager_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 "reflect" 21 "testing" 22 "time" 23 24 "github.com/hyperledger/fabric/common/configtx" 25 genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig" 26 "github.com/hyperledger/fabric/common/configtx/tool/provisional" 27 mockcrypto "github.com/hyperledger/fabric/common/mocks/crypto" 28 "github.com/hyperledger/fabric/msp" 29 "github.com/hyperledger/fabric/orderer/ledger" 30 ramledger "github.com/hyperledger/fabric/orderer/ledger/ram" 31 cb "github.com/hyperledger/fabric/protos/common" 32 ab "github.com/hyperledger/fabric/protos/orderer" 33 "github.com/hyperledger/fabric/protos/utils" 34 35 "errors" 36 37 logging "github.com/op/go-logging" 38 "github.com/stretchr/testify/assert" 39 ) 40 41 var conf *genesisconfig.Profile 42 var genesisBlock = cb.NewBlock(0, nil) // *cb.Block 43 var mockSigningIdentity msp.SigningIdentity 44 45 func init() { 46 conf = genesisconfig.Load(genesisconfig.SampleInsecureProfile) 47 logging.SetLevel(logging.DEBUG, "") 48 genesisBlock = provisional.New(conf).GenesisBlock() 49 mockSigningIdentity, _ = msp.NewNoopMsp().GetDefaultSigningIdentity() 50 } 51 52 func mockCrypto() *mockCryptoHelper { 53 return &mockCryptoHelper{LocalSigner: mockcrypto.FakeLocalSigner} 54 } 55 56 type mockCryptoHelper struct { 57 *mockcrypto.LocalSigner 58 } 59 60 func (mch mockCryptoHelper) VerifySignature(sd *cb.SignedData) error { 61 return nil 62 } 63 64 func mockCryptoRejector() *mockCryptoRejectorHelper { 65 return &mockCryptoRejectorHelper{LocalSigner: mockcrypto.FakeLocalSigner} 66 } 67 68 type mockCryptoRejectorHelper struct { 69 *mockcrypto.LocalSigner 70 } 71 72 func (mch mockCryptoRejectorHelper) VerifySignature(sd *cb.SignedData) error { 73 return errors.New("Nope") 74 } 75 76 func NewRAMLedgerAndFactory(maxSize int) (ledger.Factory, ledger.ReadWriter) { 77 rlf := ramledger.New(10) 78 rl, err := rlf.GetOrCreate(provisional.TestChainID) 79 if err != nil { 80 panic(err) 81 } 82 err = rl.Append(genesisBlock) 83 if err != nil { 84 panic(err) 85 } 86 return rlf, rl 87 } 88 89 func NewRAMLedger(maxSize int) ledger.ReadWriter { 90 _, rl := NewRAMLedgerAndFactory(maxSize) 91 return rl 92 } 93 94 // Tests for a normal chain which contains 3 config transactions and other normal transactions to make sure the right one returned 95 func TestGetConfigTx(t *testing.T) { 96 rl := NewRAMLedger(10) 97 for i := 0; i < 5; i++ { 98 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, i)})) 99 } 100 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)})) 101 ctx := makeConfigTx(provisional.TestChainID, 6) 102 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{ctx})) 103 104 block := ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)}) 105 block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 7})}) 106 rl.Append(block) 107 108 pctx := getConfigTx(rl) 109 110 if !reflect.DeepEqual(ctx, pctx) { 111 t.Fatalf("Did not select most recent config transaction") 112 } 113 } 114 115 // Tests a chain which contains blocks with multi-transactions mixed with config txs, and a single tx which is not a config tx, none count as config blocks so nil should return 116 func TestGetConfigTxFailure(t *testing.T) { 117 rl := NewRAMLedger(10) 118 for i := 0; i < 10; i++ { 119 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{ 120 makeNormalTx(provisional.TestChainID, i), 121 makeConfigTx(provisional.TestChainID, i), 122 })) 123 } 124 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)})) 125 defer func() { 126 if recover() == nil { 127 t.Fatalf("Should have panic-ed because there was no config tx") 128 } 129 }() 130 getConfigTx(rl) 131 132 } 133 134 // This test essentially brings the entire system up and is ultimately what main.go will replicate 135 func TestNoSystemChain(t *testing.T) { 136 defer func() { 137 if recover() == nil { 138 t.Fatalf("Should have panicked when starting without a system chain") 139 } 140 }() 141 142 lf := ramledger.New(10) 143 144 consenters := make(map[string]Consenter) 145 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 146 147 NewManagerImpl(lf, consenters, mockCrypto()) 148 } 149 150 // This test essentially brings the entire system up and is ultimately what main.go will replicate 151 func TestManagerImpl(t *testing.T) { 152 lf, rl := NewRAMLedgerAndFactory(10) 153 154 consenters := make(map[string]Consenter) 155 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 156 157 manager := NewManagerImpl(lf, consenters, mockCrypto()) 158 159 _, ok := manager.GetChain("Fake") 160 if ok { 161 t.Errorf("Should not have found a chain that was not created") 162 } 163 164 chainSupport, ok := manager.GetChain(provisional.TestChainID) 165 166 if !ok { 167 t.Fatalf("Should have gotten chain which was initialized by ramledger") 168 } 169 170 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 171 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 172 messages[i] = makeNormalTx(provisional.TestChainID, i) 173 } 174 175 for _, message := range messages { 176 chainSupport.Enqueue(message) 177 } 178 179 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 180 select { 181 case <-it.ReadyChan(): 182 block, status := it.Next() 183 if status != cb.Status_SUCCESS { 184 t.Fatalf("Could not retrieve block") 185 } 186 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 187 if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) { 188 t.Errorf("Block contents wrong at index %d", i) 189 } 190 } 191 case <-time.After(time.Second): 192 t.Fatalf("Block 1 not produced after timeout") 193 } 194 } 195 196 /* 197 // This test makes sure that the signature filter works 198 func TestSignatureFilter(t *testing.T) { 199 lf, rl := NewRAMLedgerAndFactory(10) 200 201 consenters := make(map[string]Consenter) 202 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 203 204 manager := NewManagerImpl(lf, consenters, mockCryptoRejector()) 205 206 cs, ok := manager.GetChain(provisional.TestChainID) 207 208 if !ok { 209 t.Fatalf("Should have gotten chain which was initialized by ramledger") 210 } 211 212 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 213 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 214 messages[i] = makeSignaturelessTx(provisional.TestChainID, i) 215 } 216 217 for _, message := range messages { 218 cs.Enqueue(message) 219 } 220 221 // Causes the consenter thread to exit after it processes all messages 222 close(cs.(*chainSupport).chain.(*mockChain).queue) 223 224 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 225 select { 226 case <-it.ReadyChan(): 227 // Will unblock if a block is created 228 t.Fatalf("Block 1 should not have been created") 229 case <-cs.(*chainSupport).chain.(*mockChain).done: 230 // Will unblock once the consenter thread has exited 231 } 232 } 233 */ 234 235 // This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain 236 func TestNewChain(t *testing.T) { 237 lf, rl := NewRAMLedgerAndFactory(10) 238 239 consenters := make(map[string]Consenter) 240 consenters[conf.Orderer.OrdererType] = &mockConsenter{} 241 242 manager := NewManagerImpl(lf, consenters, mockCrypto()) 243 244 newChainID := "TestNewChain" 245 246 envConfigUpdate, err := configtx.MakeChainCreationTransaction(newChainID, genesisconfig.SampleConsortiumName, mockSigningIdentity) 247 assert.NoError(t, err, "Constructing chain creation tx") 248 249 cm, err := manager.NewChannelConfig(envConfigUpdate) 250 assert.NoError(t, err, "Constructing initial channel config") 251 252 configEnv, err := cm.ProposeConfigUpdate(envConfigUpdate) 253 assert.NoError(t, err, "Proposing initial update") 254 255 ingressTx, err := utils.CreateSignedEnvelope(cb.HeaderType_CONFIG, newChainID, mockCrypto(), configEnv, msgVersion, epoch) 256 assert.NoError(t, err, "Creating ingresstx") 257 258 wrapped := wrapConfigTx(ingressTx) 259 260 chainSupport, ok := manager.GetChain(manager.SystemChannelID()) 261 assert.True(t, ok, "Could not find system channel") 262 chainSupport.Enqueue(wrapped) 263 264 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 265 select { 266 case <-it.ReadyChan(): 267 block, status := it.Next() 268 if status != cb.Status_SUCCESS { 269 t.Fatalf("Could not retrieve block") 270 } 271 if len(block.Data.Data) != 1 { 272 t.Fatalf("Should have had only one message in the orderer transaction block") 273 } 274 275 assert.Equal(t, wrapped, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Orderer config block contains wrong transaction") 276 case <-time.After(time.Second): 277 t.Fatalf("Block 1 not produced after timeout in system chain") 278 } 279 280 chainSupport, ok = manager.GetChain(newChainID) 281 282 if !ok { 283 t.Fatalf("Should have gotten new chain which was created") 284 } 285 286 messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount) 287 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 288 messages[i] = makeNormalTx(newChainID, i) 289 } 290 291 for _, message := range messages { 292 chainSupport.Enqueue(message) 293 } 294 295 it, _ = chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}}) 296 select { 297 case <-it.ReadyChan(): 298 block, status := it.Next() 299 if status != cb.Status_SUCCESS { 300 t.Fatalf("Could not retrieve new chain genesis block") 301 } 302 if len(block.Data.Data) != 1 { 303 t.Fatalf("Should have had only one message in the new genesis block") 304 } 305 306 assert.Equal(t, ingressTx, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Genesis block contains wrong transaction") 307 case <-time.After(time.Second): 308 t.Fatalf("Block 1 not produced after timeout in system chain") 309 } 310 311 select { 312 case <-it.ReadyChan(): 313 block, status := it.Next() 314 if status != cb.Status_SUCCESS { 315 t.Fatalf("Could not retrieve block on new chain") 316 } 317 for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ { 318 if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) { 319 t.Errorf("Block contents wrong at index %d in new chain", i) 320 } 321 } 322 case <-time.After(time.Second): 323 t.Fatalf("Block 1 not produced after timeout on new chain") 324 } 325 }