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  }