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  }