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 })