github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/orderer/consensus/etcdraft/validator_test.go (about)

     1  /*
     2   Copyright hechain All Rights Reserved.
     3  
     4   SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package etcdraft_test
     8  
     9  import (
    10  	"io/ioutil"
    11  	"os"
    12  	"time"
    13  
    14  	"github.com/golang/protobuf/proto"
    15  	. "github.com/onsi/ginkgo"
    16  	. "github.com/onsi/gomega"
    17  
    18  	"github.com/hechain20/hechain/bccsp"
    19  	"github.com/hechain20/hechain/bccsp/sw"
    20  	"github.com/hechain20/hechain/common/channelconfig"
    21  	"github.com/hechain20/hechain/common/crypto/tlsgen"
    22  	"github.com/hechain20/hechain/orderer/consensus/etcdraft"
    23  	"github.com/hechain20/hechain/orderer/consensus/etcdraft/mocks"
    24  	consensusmocks "github.com/hechain20/hechain/orderer/consensus/mocks"
    25  	raftprotos "github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
    26  )
    27  
    28  func makeOrdererOrg(caCert []byte) *mocks.OrdererOrg {
    29  	ordererOrg := &mocks.OrdererOrg{}
    30  	mockMSP := &mocks.MSP{}
    31  	mockMSP.GetTLSRootCertsReturns([][]byte{caCert})
    32  	ordererOrg.MSPReturns(mockMSP)
    33  	return ordererOrg
    34  }
    35  
    36  var _ = Describe("Metadata Validation", func() {
    37  	var (
    38  		chain             *etcdraft.Chain
    39  		tlsCA             tlsgen.CA
    40  		channelID         string
    41  		consenterMetadata *raftprotos.ConfigMetadata
    42  		consenters        map[uint64]*raftprotos.Consenter
    43  		support           *consensusmocks.FakeConsenterSupport
    44  		dataDir           string
    45  		err               error
    46  		cryptoProvider    bccsp.BCCSP
    47  		meta              *raftprotos.BlockMetadata
    48  	)
    49  
    50  	BeforeEach(func() {
    51  		channelID = "test-channel"
    52  
    53  		cryptoProvider, err = sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
    54  		Expect(err).NotTo(HaveOccurred())
    55  
    56  		dataDir, err = ioutil.TempDir("", "wal-")
    57  		Expect(err).NotTo(HaveOccurred())
    58  
    59  		tlsCA, err = tlsgen.NewCA()
    60  		Expect(err).NotTo(HaveOccurred())
    61  
    62  		support = &consensusmocks.FakeConsenterSupport{}
    63  		support.ChannelIDReturns(channelID)
    64  		consenterMetadata = createMetadata(3, tlsCA)
    65  		mockOrdererConfig := mockOrdererWithTLSRootCert(time.Hour, marshalOrPanic(consenterMetadata), tlsCA)
    66  		support.SharedConfigReturns(mockOrdererConfig)
    67  
    68  		meta = &raftprotos.BlockMetadata{
    69  			ConsenterIds:    make([]uint64, len(consenterMetadata.Consenters)),
    70  			NextConsenterId: 1,
    71  		}
    72  
    73  		for i := range meta.ConsenterIds {
    74  			meta.ConsenterIds[i] = meta.NextConsenterId
    75  			meta.NextConsenterId++
    76  		}
    77  
    78  		consenters = map[uint64]*raftprotos.Consenter{}
    79  		for i, c := range consenterMetadata.Consenters {
    80  			consenters[meta.ConsenterIds[i]] = c
    81  		}
    82  	})
    83  
    84  	JustBeforeEach(func() {
    85  		c := newChain(10*time.Second, channelID, dataDir, 1, meta, consenters, cryptoProvider, support, nil)
    86  		c.init()
    87  		chain = c.Chain
    88  		chain.ActiveNodes.Store([]uint64{1, 2, 3})
    89  	})
    90  
    91  	AfterEach(func() {
    92  		os.RemoveAll(dataDir)
    93  	})
    94  
    95  	When("determining parameter well-formedness", func() {
    96  		It("succeeds when new orderer config is nil", func() {
    97  			Expect(chain.ValidateConsensusMetadata(mockOrderer(nil), mockOrderer(nil), false)).To(Succeed())
    98  		})
    99  
   100  		It("fails when new orderer config is not nil while old orderer config is nil", func() {
   101  			newOrdererConf := mockOrderer([]byte("test"))
   102  			Expect(func() {
   103  				chain.ValidateConsensusMetadata(nil, newOrdererConf, false)
   104  			}).To(Panic())
   105  		})
   106  
   107  		It("fails when new orderer config is not nil while old config metadata is nil", func() {
   108  			newOrdererConf := mockOrderer([]byte("test"))
   109  			Expect(func() {
   110  				chain.ValidateConsensusMetadata(mockOrderer(nil), newOrdererConf, false)
   111  			}).To(Panic())
   112  		})
   113  
   114  		It("fails when old consensus metadata is not well-formed", func() {
   115  			oldOrdererConf := mockOrderer([]byte("test"))
   116  			newOrdererConf := mockOrderer([]byte("test"))
   117  			Expect(func() {
   118  				chain.ValidateConsensusMetadata(oldOrdererConf, newOrdererConf, false)
   119  			}).To(Panic())
   120  		})
   121  
   122  		It("fails when new consensus metadata is not well-formed", func() {
   123  			oldBytes, _ := proto.Marshal(&raftprotos.ConfigMetadata{})
   124  			oldOrdererConf := mockOrderer(oldBytes)
   125  			newOrdererConf := mockOrderer([]byte("test"))
   126  			Expect(chain.ValidateConsensusMetadata(oldOrdererConf, newOrdererConf, false)).NotTo(Succeed())
   127  		})
   128  	})
   129  
   130  	Context("valid old consensus metadata", func() {
   131  		var (
   132  			metadata         raftprotos.ConfigMetadata
   133  			oldOrdererConfig *mocks.OrdererConfig
   134  			newOrdererConfig *mocks.OrdererConfig
   135  			newChannel       bool
   136  		)
   137  
   138  		BeforeEach(func() {
   139  			metadata = raftprotos.ConfigMetadata{
   140  				Options: &raftprotos.Options{
   141  					TickInterval:         "500ms",
   142  					ElectionTick:         10,
   143  					HeartbeatTick:        1,
   144  					MaxInflightBlocks:    5,
   145  					SnapshotIntervalSize: 20 * 1024 * 1024, // 20 MB
   146  				},
   147  				Consenters: []*raftprotos.Consenter{
   148  					{
   149  						Host:          "host1",
   150  						Port:          10001,
   151  						ClientTlsCert: clientTLSCert(tlsCA),
   152  						ServerTlsCert: serverTLSCert(tlsCA),
   153  					},
   154  					{
   155  						Host:          "host2",
   156  						Port:          10002,
   157  						ClientTlsCert: clientTLSCert(tlsCA),
   158  						ServerTlsCert: serverTLSCert(tlsCA),
   159  					},
   160  					{
   161  						Host:          "host3",
   162  						Port:          10003,
   163  						ClientTlsCert: clientTLSCert(tlsCA),
   164  						ServerTlsCert: serverTLSCert(tlsCA),
   165  					},
   166  				},
   167  			}
   168  
   169  			oldBytes, err := proto.Marshal(&metadata)
   170  			Expect(err).NotTo(HaveOccurred())
   171  			oldOrdererConfig = mockOrderer(oldBytes)
   172  			org1 := makeOrdererOrg(tlsCA.CertBytes())
   173  			oldOrdererConfig.OrganizationsReturns(map[string]channelconfig.OrdererOrg{
   174  				"org1": org1,
   175  			})
   176  
   177  			newOrdererConfig = mockOrderer(oldBytes)
   178  			newOrdererConfig.OrganizationsReturns(map[string]channelconfig.OrdererOrg{
   179  				"org1": org1,
   180  			})
   181  
   182  			newChannel = false
   183  		})
   184  
   185  		It("fails when new consensus metadata has invalid options", func() {
   186  			// NOTE: we are not checking all failures here since tests for CheckConfigMetadata does that
   187  			newMetadata := metadata
   188  			newMetadata.Options.TickInterval = ""
   189  			newBytes, err := proto.Marshal(&newMetadata)
   190  			Expect(err).NotTo(HaveOccurred())
   191  			newOrdererConfig.ConsensusMetadataReturns(newBytes)
   192  			Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   193  		})
   194  
   195  		Context("new channel creation", func() {
   196  			BeforeEach(func() {
   197  				newChannel = true
   198  			})
   199  
   200  			It("fails when the new consenters are an empty set", func() {
   201  				newMetadata := metadata
   202  				newMetadata.Consenters = []*raftprotos.Consenter{}
   203  				newBytes, err := proto.Marshal(&newMetadata)
   204  				Expect(err).NotTo(HaveOccurred())
   205  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   206  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   207  			})
   208  
   209  			It("succeeds when the new consenters are the same as the existing consenters", func() {
   210  				newMetadata := metadata
   211  				newBytes, err := proto.Marshal(&newMetadata)
   212  				Expect(err).NotTo(HaveOccurred())
   213  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   214  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   215  			})
   216  
   217  			It("succeeds when the new consenters are a subset of the existing consenters", func() {
   218  				newMetadata := metadata
   219  				newMetadata.Consenters = newMetadata.Consenters[:2]
   220  				newBytes, err := proto.Marshal(&newMetadata)
   221  				Expect(err).NotTo(HaveOccurred())
   222  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   223  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   224  			})
   225  
   226  			It("fails when the new consenters are not a subset of the existing consenters", func() {
   227  				newMetadata := metadata
   228  				newMetadata.Consenters[2].ClientTlsCert = clientTLSCert(tlsCA)
   229  				newBytes, err := proto.Marshal(&newMetadata)
   230  				Expect(err).NotTo(HaveOccurred())
   231  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   232  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   233  			})
   234  
   235  			It("fails when the new consenter has certificate which not signed by any CA of an orderer org", func() {
   236  				anotherCa, err := tlsgen.NewCA()
   237  				Expect(err).NotTo(HaveOccurred())
   238  				newMetadata := metadata
   239  				newMetadata.Consenters[2].ClientTlsCert = clientTLSCert(anotherCa)
   240  				newBytes, err := proto.Marshal(&newMetadata)
   241  				Expect(err).NotTo(HaveOccurred())
   242  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   243  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   244  			})
   245  
   246  			It("succeeds when the new consenters are a subset of the system consenters and certificates signed by MSP participant on a channel", func() {
   247  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   248  			})
   249  		})
   250  
   251  		Context("config update on a channel", func() {
   252  			BeforeEach(func() {
   253  				newChannel = false
   254  				chain.ActiveNodes.Store([]uint64{1, 2, 3})
   255  			})
   256  
   257  			It("fails when the new consenters are an empty set", func() {
   258  				newMetadata := metadata
   259  				// NOTE: This also takes care of the case when we remove node from a singleton consenter set
   260  				newMetadata.Consenters = []*raftprotos.Consenter{}
   261  				newBytes, err := proto.Marshal(&newMetadata)
   262  				Expect(err).NotTo(HaveOccurred())
   263  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   264  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   265  			})
   266  
   267  			It("succeeds when the new consenters are the same as the existing consenters", func() {
   268  				newMetadata := metadata
   269  				newBytes, err := proto.Marshal(&newMetadata)
   270  				Expect(err).NotTo(HaveOccurred())
   271  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   272  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   273  			})
   274  
   275  			It("succeeds on addition of a single consenter", func() {
   276  				newMetadata := metadata
   277  				newMetadata.Consenters = append(newMetadata.Consenters, &raftprotos.Consenter{
   278  					Host:          "host4",
   279  					Port:          10004,
   280  					ClientTlsCert: clientTLSCert(tlsCA),
   281  					ServerTlsCert: serverTLSCert(tlsCA),
   282  				})
   283  				newBytes, err := proto.Marshal(&newMetadata)
   284  				Expect(err).NotTo(HaveOccurred())
   285  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   286  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   287  			})
   288  
   289  			It("fails on addition of more than one consenter", func() {
   290  				newMetadata := metadata
   291  				newMetadata.Consenters = append(newMetadata.Consenters,
   292  					&raftprotos.Consenter{
   293  						Host:          "host4",
   294  						Port:          10004,
   295  						ClientTlsCert: clientTLSCert(tlsCA),
   296  						ServerTlsCert: serverTLSCert(tlsCA),
   297  					},
   298  					&raftprotos.Consenter{
   299  						Host:          "host5",
   300  						Port:          10005,
   301  						ClientTlsCert: clientTLSCert(tlsCA),
   302  						ServerTlsCert: serverTLSCert(tlsCA),
   303  					},
   304  				)
   305  				newBytes, err := proto.Marshal(&newMetadata)
   306  				Expect(err).NotTo(HaveOccurred())
   307  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   308  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   309  			})
   310  
   311  			It("succeeds on removal of a single consenter", func() {
   312  				newMetadata := metadata
   313  				newMetadata.Consenters = newMetadata.Consenters[:2]
   314  				newBytes, err := proto.Marshal(&newMetadata)
   315  				Expect(err).NotTo(HaveOccurred())
   316  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   317  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   318  			})
   319  
   320  			It("fails on removal of more than one consenter", func() {
   321  				newMetadata := metadata
   322  				newMetadata.Consenters = newMetadata.Consenters[:1]
   323  				newBytes, err := proto.Marshal(&newMetadata)
   324  				Expect(err).NotTo(HaveOccurred())
   325  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   326  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).NotTo(Succeed())
   327  			})
   328  
   329  			It("succeeds on rotating certs in case of both addition and removal of a node each to reuse the raft NodeId", func() {
   330  				newMetadata := metadata
   331  				newMetadata.Consenters = append(newMetadata.Consenters[:2], &raftprotos.Consenter{
   332  					Host:          "host4",
   333  					Port:          10004,
   334  					ClientTlsCert: clientTLSCert(tlsCA),
   335  					ServerTlsCert: serverTLSCert(tlsCA),
   336  				})
   337  				newBytes, err := proto.Marshal(&newMetadata)
   338  				Expect(err).NotTo(HaveOccurred())
   339  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   340  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   341  			})
   342  
   343  			It("succeeds on removal of inactive node in 2/3 cluster", func() {
   344  				chain.ActiveNodes.Store([]uint64{1, 2})
   345  				newMetadata := metadata
   346  				newMetadata.Consenters = newMetadata.Consenters[:2]
   347  				newBytes, err := proto.Marshal(&newMetadata)
   348  				Expect(err).NotTo(HaveOccurred())
   349  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   350  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   351  			})
   352  
   353  			It("fails on removal of active node in 2/3 cluster", func() {
   354  				chain.ActiveNodes.Store([]uint64{1, 2})
   355  				newMetadata := metadata
   356  				newMetadata.Consenters = newMetadata.Consenters[1:]
   357  				newBytes, err := proto.Marshal(&newMetadata)
   358  				Expect(err).NotTo(HaveOccurred())
   359  				newOrdererConfig.ConsensusMetadataReturns(newBytes)
   360  				Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(
   361  					MatchError("2 out of 3 nodes are alive, configuration will result in quorum loss"))
   362  			})
   363  
   364  			When("node id starts from 2", func() {
   365  				// this test case is mainly to assure that validator does NOT assume node ID to
   366  				// always start from 1. Consider following case:
   367  				// - we have [2, 3, 4] in consenter set
   368  				// - 4 is inactive and subject to remove, which should NOT result in quorum loss
   369  				// - if validator assumes node to start from 1, it would incorrectly conclude that
   370  				//   node 3 is to be removed, therefore rejecting such request
   371  				// - instead, validator should recognize that 4 is the one to be removed, which is
   372  				//   not harmful to network and happily allows it
   373  
   374  				BeforeEach(func() {
   375  					meta = &raftprotos.BlockMetadata{
   376  						ConsenterIds:    make([]uint64, len(consenterMetadata.Consenters)),
   377  						NextConsenterId: 2, // id starts from 2
   378  					}
   379  
   380  					for i := range meta.ConsenterIds {
   381  						meta.ConsenterIds[i] = meta.NextConsenterId
   382  						meta.NextConsenterId++
   383  					}
   384  
   385  					consenters = map[uint64]*raftprotos.Consenter{}
   386  					for i, c := range consenterMetadata.Consenters {
   387  						consenters[meta.ConsenterIds[i]] = c
   388  					}
   389  				})
   390  
   391  				It("succeeds on removal of inactive node in 2/3 cluster", func() {
   392  					chain.ActiveNodes.Store([]uint64{2, 3}) // 4 is inactive
   393  					newMetadata := metadata
   394  					newMetadata.Consenters = newMetadata.Consenters[:2]
   395  					newBytes, err := proto.Marshal(&newMetadata)
   396  					Expect(err).NotTo(HaveOccurred())
   397  					newOrdererConfig.ConsensusMetadataReturns(newBytes)
   398  					Expect(chain.ValidateConsensusMetadata(oldOrdererConfig, newOrdererConfig, newChannel)).To(Succeed())
   399  				})
   400  			})
   401  		})
   402  	})
   403  })