github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/configtx/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 configtx
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/hyperledger/fabric/common/configtx/api"
    24  	mockconfigtx "github.com/hyperledger/fabric/common/mocks/configtx"
    25  	mockpolicies "github.com/hyperledger/fabric/common/mocks/policies"
    26  	"github.com/hyperledger/fabric/common/policies"
    27  	cb "github.com/hyperledger/fabric/protos/common"
    28  	"github.com/hyperledger/fabric/protos/utils"
    29  
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  var defaultChain = "default.chain.id"
    34  
    35  func defaultInitializer() *mockconfigtx.Initializer {
    36  	return &mockconfigtx.Initializer{
    37  		Resources: mockconfigtx.Resources{
    38  			PolicyManagerVal: &mockpolicies.Manager{
    39  				Policy: &mockpolicies.Policy{},
    40  			},
    41  		},
    42  		PolicyProposerVal: &mockconfigtx.PolicyProposer{
    43  			Transactional: mockconfigtx.Transactional{},
    44  		},
    45  		ValueProposerVal: &mockconfigtx.ValueProposer{
    46  			Transactional: mockconfigtx.Transactional{},
    47  		},
    48  	}
    49  }
    50  
    51  type configPair struct {
    52  	key   string
    53  	value *cb.ConfigValue
    54  }
    55  
    56  func makeConfigPair(id, modificationPolicy string, lastModified uint64, data []byte) *configPair {
    57  	return &configPair{
    58  		key: id,
    59  		value: &cb.ConfigValue{
    60  			ModPolicy: modificationPolicy,
    61  			Version:   lastModified,
    62  			Value:     data,
    63  		},
    64  	}
    65  }
    66  
    67  func makeEnvelopeConfig(channelID string, configPairs ...*configPair) *cb.Envelope {
    68  	channelGroup := cb.NewConfigGroup()
    69  	for _, pair := range configPairs {
    70  		channelGroup.Values[pair.key] = pair.value
    71  	}
    72  
    73  	return &cb.Envelope{
    74  		Payload: utils.MarshalOrPanic(&cb.Payload{
    75  			Header: &cb.Header{
    76  				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
    77  					Type:      int32(cb.HeaderType_CONFIG),
    78  					ChannelId: channelID,
    79  				}),
    80  			},
    81  			Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{
    82  				Config: &cb.Config{
    83  					ChannelGroup: channelGroup,
    84  				},
    85  			}),
    86  		}),
    87  	}
    88  }
    89  
    90  func makeConfigSet(configPairs ...*configPair) *cb.ConfigGroup {
    91  	result := cb.NewConfigGroup()
    92  	for _, pair := range configPairs {
    93  		result.Values[pair.key] = pair.value
    94  	}
    95  	return result
    96  }
    97  
    98  func makeConfigUpdateEnvelope(chainID string, readSet, writeSet *cb.ConfigGroup) *cb.Envelope {
    99  	return &cb.Envelope{
   100  		Payload: utils.MarshalOrPanic(&cb.Payload{
   101  			Header: &cb.Header{
   102  				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
   103  					Type: int32(cb.HeaderType_CONFIG_UPDATE),
   104  				}),
   105  			},
   106  			Data: utils.MarshalOrPanic(&cb.ConfigUpdateEnvelope{
   107  				ConfigUpdate: utils.MarshalOrPanic(&cb.ConfigUpdate{
   108  					ChannelId: chainID,
   109  					ReadSet:   readSet,
   110  					WriteSet:  writeSet,
   111  				}),
   112  			}),
   113  		}),
   114  	}
   115  }
   116  
   117  func TestCallback(t *testing.T) {
   118  	var calledBack api.Manager
   119  	callback := func(m api.Manager) {
   120  		calledBack = m
   121  	}
   122  
   123  	cm, err := NewManagerImpl(
   124  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   125  		defaultInitializer(), []func(api.Manager){callback})
   126  
   127  	if err != nil {
   128  		t.Fatalf("Error constructing config manager: %s", err)
   129  	}
   130  
   131  	if calledBack != cm {
   132  		t.Fatalf("Should have called back with the correct manager")
   133  	}
   134  }
   135  
   136  func TestEmptyChannel(t *testing.T) {
   137  	_, err := NewManagerImpl(&cb.Envelope{
   138  		Payload: utils.MarshalOrPanic(&cb.Payload{
   139  			Header: &cb.Header{
   140  				ChannelHeader: utils.MarshalOrPanic(&cb.ChannelHeader{
   141  					Type:      int32(cb.HeaderType_CONFIG),
   142  					ChannelId: "foo",
   143  				}),
   144  			},
   145  			Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{
   146  				Config: &cb.Config{},
   147  			}),
   148  		}),
   149  	}, defaultInitializer(), nil)
   150  	assert.Error(t, err)
   151  }
   152  
   153  // TestDifferentChainID tests that a config update for a different chain ID fails
   154  func TestDifferentChainID(t *testing.T) {
   155  	cm, err := NewManagerImpl(
   156  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   157  		defaultInitializer(), nil)
   158  
   159  	if err != nil {
   160  		t.Fatalf("Error constructing config manager: %s", err)
   161  	}
   162  
   163  	newConfig := makeConfigUpdateEnvelope("wrongChain", makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo"))))
   164  
   165  	_, err = cm.ProposeConfigUpdate(newConfig)
   166  	if err == nil {
   167  		t.Error("Should have errored when proposing a new config set the wrong chain ID")
   168  	}
   169  }
   170  
   171  // TestOldConfigReplay tests that resubmitting a config for a sequence number which is not newer is ignored
   172  func TestOldConfigReplay(t *testing.T) {
   173  	cm, err := NewManagerImpl(
   174  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   175  		defaultInitializer(), nil)
   176  
   177  	if err != nil {
   178  		t.Fatalf("Error constructing config manager: %s", err)
   179  	}
   180  
   181  	newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))))
   182  
   183  	_, err = cm.ProposeConfigUpdate(newConfig)
   184  	if err == nil {
   185  		t.Error("Should have errored when proposing a config that is not a newer sequence number")
   186  	}
   187  }
   188  
   189  // TestValidConfigChange tests the happy path of updating a config value with no defaultModificationPolicy
   190  func TestValidConfigChange(t *testing.T) {
   191  	cm, err := NewManagerImpl(
   192  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   193  		defaultInitializer(), nil)
   194  
   195  	if err != nil {
   196  		t.Fatalf("Error constructing config manager: %s", err)
   197  	}
   198  
   199  	newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo"))))
   200  
   201  	configEnv, err := cm.ProposeConfigUpdate(newConfig)
   202  	if err != nil {
   203  		t.Errorf("Should not have errored proposing config: %s", err)
   204  	}
   205  
   206  	err = cm.Validate(configEnv)
   207  	if err != nil {
   208  		t.Errorf("Should not have errored validating config: %s", err)
   209  	}
   210  
   211  	err = cm.Apply(configEnv)
   212  	if err != nil {
   213  		t.Errorf("Should not have errored applying config: %s", err)
   214  	}
   215  }
   216  
   217  // TestConfigChangeRegressedSequence tests to make sure that a new config cannot roll back one of the
   218  // config values while advancing another
   219  func TestConfigChangeRegressedSequence(t *testing.T) {
   220  	cm, err := NewManagerImpl(
   221  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
   222  		defaultInitializer(), nil)
   223  
   224  	if err != nil {
   225  		t.Fatalf("Error constructing config manager: %s", err)
   226  	}
   227  
   228  	newConfig := makeConfigUpdateEnvelope(
   229  		defaultChain,
   230  		makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))),
   231  		makeConfigSet(makeConfigPair("bar", "bar", 2, []byte("bar"))),
   232  	)
   233  
   234  	_, err = cm.ProposeConfigUpdate(newConfig)
   235  	if err == nil {
   236  		t.Error("Should have errored proposing config because foo's sequence number regressed")
   237  	}
   238  }
   239  
   240  // TestConfigChangeOldSequence tests to make sure that a new config cannot roll back one of the
   241  // config values while advancing another
   242  func TestConfigChangeOldSequence(t *testing.T) {
   243  	cm, err := NewManagerImpl(
   244  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 1, []byte("foo"))),
   245  		defaultInitializer(), nil)
   246  
   247  	if err != nil {
   248  		t.Fatalf("Error constructing config manager: %s", err)
   249  	}
   250  
   251  	newConfig := makeConfigUpdateEnvelope(
   252  		defaultChain,
   253  		makeConfigSet(),
   254  		makeConfigSet(
   255  			makeConfigPair("foo", "foo", 2, []byte("foo")),
   256  			makeConfigPair("bar", "bar", 1, []byte("bar")),
   257  		),
   258  	)
   259  
   260  	_, err = cm.ProposeConfigUpdate(newConfig)
   261  	if err == nil {
   262  		t.Error("Should have errored proposing config because bar was new but its sequence number was old")
   263  	}
   264  }
   265  
   266  // TestConfigPartialUpdate tests to make sure that a new config can set only part
   267  // of the config and still be accepted
   268  func TestConfigPartialUpdate(t *testing.T) {
   269  	cm, err := NewManagerImpl(
   270  		makeEnvelopeConfig(
   271  			defaultChain,
   272  			makeConfigPair("foo", "foo", 0, []byte("foo")),
   273  			makeConfigPair("bar", "bar", 0, []byte("bar")),
   274  		),
   275  		defaultInitializer(), nil)
   276  
   277  	if err != nil {
   278  		t.Fatalf("Error constructing config manager: %s", err)
   279  	}
   280  
   281  	newConfig := makeConfigUpdateEnvelope(
   282  		defaultChain,
   283  		makeConfigSet(),
   284  		makeConfigSet(makeConfigPair("bar", "bar", 1, []byte("bar"))),
   285  	)
   286  
   287  	_, err = cm.ProposeConfigUpdate(newConfig)
   288  	assert.NoError(t, err, "Should have allowed partial update")
   289  }
   290  
   291  // TestEmptyConfigUpdate tests to make sure that an empty config is rejected as an update
   292  func TestEmptyConfigUpdate(t *testing.T) {
   293  	cm, err := NewManagerImpl(
   294  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   295  		defaultInitializer(), nil)
   296  
   297  	if err != nil {
   298  		t.Fatalf("Error constructing config manager: %s", err)
   299  	}
   300  
   301  	newConfig := &cb.Envelope{}
   302  
   303  	_, err = cm.ProposeConfigUpdate(newConfig)
   304  	if err == nil {
   305  		t.Error("Should not errored proposing config because new config is empty")
   306  	}
   307  }
   308  
   309  // TestSilentConfigModification tests to make sure that even if a validly signed new config for an existing sequence number
   310  // is substituted into an otherwise valid new config, that the new config is rejected for attempting a modification without
   311  // increasing the config item's LastModified
   312  func TestSilentConfigModification(t *testing.T) {
   313  	cm, err := NewManagerImpl(
   314  		makeEnvelopeConfig(
   315  			defaultChain,
   316  			makeConfigPair("foo", "foo", 0, []byte("foo")),
   317  			makeConfigPair("bar", "bar", 0, []byte("bar")),
   318  		),
   319  		defaultInitializer(), nil)
   320  
   321  	if err != nil {
   322  		t.Fatalf("Error constructing config manager: %s", err)
   323  	}
   324  
   325  	newConfig := makeConfigUpdateEnvelope(
   326  		defaultChain,
   327  		makeConfigSet(),
   328  		makeConfigSet(
   329  			makeConfigPair("foo", "foo", 0, []byte("different")),
   330  			makeConfigPair("bar", "bar", 1, []byte("bar")),
   331  		),
   332  	)
   333  
   334  	_, err = cm.ProposeConfigUpdate(newConfig)
   335  	if err == nil {
   336  		t.Error("Should have errored proposing config because foo was silently modified (despite modification allowed by policy)")
   337  	}
   338  }
   339  
   340  // TestConfigChangeViolatesPolicy checks to make sure that if policy rejects the validation of a config item that
   341  // it is rejected in a config update
   342  func TestConfigChangeViolatesPolicy(t *testing.T) {
   343  	initializer := defaultInitializer()
   344  	cm, err := NewManagerImpl(
   345  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   346  		initializer, nil)
   347  
   348  	if err != nil {
   349  		t.Fatalf("Error constructing config manager: %s", err)
   350  	}
   351  	// Set the mock policy to error
   352  	initializer.Resources.PolicyManagerVal.Policy.Err = fmt.Errorf("err")
   353  
   354  	newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo"))))
   355  
   356  	_, err = cm.ProposeConfigUpdate(newConfig)
   357  	if err == nil {
   358  		t.Error("Should have errored proposing config because policy rejected modification")
   359  	}
   360  }
   361  
   362  // TestUnchangedConfigViolatesPolicy checks to make sure that existing config items are not revalidated against their modification policies
   363  // as the policy may have changed, certs revoked, etc. since the config was adopted.
   364  func TestUnchangedConfigViolatesPolicy(t *testing.T) {
   365  	initializer := defaultInitializer()
   366  	cm, err := NewManagerImpl(
   367  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   368  		initializer, nil)
   369  
   370  	if err != nil {
   371  		t.Fatalf("Error constructing config manager: %s", err)
   372  	}
   373  
   374  	// Set the mock policy to error
   375  	initializer.Resources.PolicyManagerVal.PolicyMap = make(map[string]policies.Policy)
   376  	initializer.Resources.PolicyManagerVal.PolicyMap["foo"] = &mockpolicies.Policy{Err: fmt.Errorf("err")}
   377  
   378  	newConfig := makeConfigUpdateEnvelope(
   379  		defaultChain,
   380  		makeConfigSet(makeConfigPair("foo", "foo", 0, []byte("foo"))),
   381  		makeConfigSet(makeConfigPair("bar", "bar", 0, []byte("foo"))),
   382  	)
   383  
   384  	configEnv, err := cm.ProposeConfigUpdate(newConfig)
   385  	if err != nil {
   386  		t.Errorf("Should not have errored proposing config, but got %s", err)
   387  	}
   388  
   389  	err = cm.Validate(configEnv)
   390  	if err != nil {
   391  		t.Errorf("Should not have errored validating config, but got %s", err)
   392  	}
   393  
   394  	err = cm.Apply(configEnv)
   395  	if err != nil {
   396  		t.Errorf("Should not have errored applying config, but got %s", err)
   397  	}
   398  }
   399  
   400  // TestInvalidProposal checks that even if the policy allows the transaction and the sequence etc. is well formed,
   401  // that if the handler does not accept the config, it is rejected
   402  func TestInvalidProposal(t *testing.T) {
   403  	initializer := defaultInitializer()
   404  	cm, err := NewManagerImpl(
   405  		makeEnvelopeConfig(defaultChain, makeConfigPair("foo", "foo", 0, []byte("foo"))),
   406  		initializer, nil)
   407  
   408  	if err != nil {
   409  		t.Fatalf("Error constructing config manager: %s", err)
   410  	}
   411  
   412  	initializer.ValueProposerVal = &mockconfigtx.ValueProposer{DeserializeError: fmt.Errorf("err")}
   413  
   414  	newConfig := makeConfigUpdateEnvelope(defaultChain, makeConfigSet(), makeConfigSet(makeConfigPair("foo", "foo", 1, []byte("foo"))))
   415  
   416  	_, err = cm.ProposeConfigUpdate(newConfig)
   417  	if err == nil {
   418  		t.Error("Should have errored proposing config because the handler rejected it")
   419  	}
   420  }
   421  
   422  // TestMissingHeader checks that a config envelope with a missing header causes the config to be rejected
   423  func TestMissingHeader(t *testing.T) {
   424  	group := cb.NewConfigGroup()
   425  	group.Values["foo"] = &cb.ConfigValue{}
   426  	_, err := NewManagerImpl(
   427  		&cb.Envelope{Payload: utils.MarshalOrPanic(&cb.Payload{Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: group}})})},
   428  		defaultInitializer(), nil)
   429  
   430  	if err == nil {
   431  		t.Error("Should have errored creating the config manager because of the missing header")
   432  	}
   433  }
   434  
   435  // TestMissingChainID checks that a config item with a missing chainID causes the config to be rejected
   436  func TestMissingChainID(t *testing.T) {
   437  	_, err := NewManagerImpl(
   438  		makeEnvelopeConfig("", makeConfigPair("foo", "foo", 0, []byte("foo"))),
   439  		defaultInitializer(), nil)
   440  
   441  	if err == nil {
   442  		t.Error("Should have errored creating the config manager because of the missing header")
   443  	}
   444  }