github.com/kaituanwang/hyperledger@v2.0.1+incompatible/orderer/consensus/etcdraft/validator_test.go (about) 1 /* 2 Copyright IBM Corp All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package etcdraft_test 8 9 import ( 10 "github.com/golang/protobuf/proto" 11 etcdraftproto "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" 12 "github.com/hyperledger/fabric/bccsp/sw" 13 "github.com/hyperledger/fabric/common/crypto/tlsgen" 14 "github.com/hyperledger/fabric/orderer/consensus/etcdraft" 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("Metadata Validation", func() { 20 var ( 21 chain *etcdraft.Chain 22 ) 23 24 BeforeEach(func() { 25 cryptoProvider, _ := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 26 chain = &etcdraft.Chain{CryptoProvider: cryptoProvider} 27 chain.ActiveNodes.Store([]uint64{}) 28 }) 29 30 When("determining parameter well-formedness", func() { 31 It("succeeds when new consensus metadata is nil", func() { 32 Expect(chain.ValidateConsensusMetadata(nil, nil, false)).To(Succeed()) 33 }) 34 35 It("fails when new consensus metadata is not nil while old consensus metadata is nil", func() { 36 Expect(func() { 37 chain.ValidateConsensusMetadata(nil, []byte("test"), false) 38 }).To(Panic()) 39 }) 40 41 It("fails when old consensus metadata is not well-formed", func() { 42 Expect(func() { 43 chain.ValidateConsensusMetadata([]byte("test"), []byte("test"), false) 44 }).To(Panic()) 45 }) 46 47 It("fails when new consensus metadata is not well-formed", func() { 48 oldBytes, _ := proto.Marshal(&etcdraftproto.ConfigMetadata{}) 49 Expect(chain.ValidateConsensusMetadata(oldBytes, []byte("test"), false)).NotTo(Succeed()) 50 }) 51 }) 52 53 Context("valid old consensus metadata", func() { 54 var ( 55 oldBytes []byte 56 oldMetadata *etcdraftproto.ConfigMetadata 57 newMetadata *etcdraftproto.ConfigMetadata 58 tlsCA tlsgen.CA 59 newChannel bool 60 ) 61 62 BeforeEach(func() { 63 tlsCA, _ = tlsgen.NewCA() 64 oldMetadata = &etcdraftproto.ConfigMetadata{ 65 Options: &etcdraftproto.Options{ 66 TickInterval: "500ms", 67 ElectionTick: 10, 68 HeartbeatTick: 1, 69 MaxInflightBlocks: 5, 70 SnapshotIntervalSize: 20 * 1024 * 1024, // 20 MB 71 }, 72 Consenters: []*etcdraftproto.Consenter{ 73 { 74 Host: "host1", 75 Port: 10001, 76 ClientTlsCert: clientTLSCert(tlsCA), 77 ServerTlsCert: serverTLSCert(tlsCA), 78 }, 79 { 80 Host: "host2", 81 Port: 10002, 82 ClientTlsCert: clientTLSCert(tlsCA), 83 ServerTlsCert: serverTLSCert(tlsCA), 84 }, 85 { 86 Host: "host3", 87 Port: 10003, 88 ClientTlsCert: clientTLSCert(tlsCA), 89 ServerTlsCert: serverTLSCert(tlsCA), 90 }, 91 }, 92 } 93 newMetadata = oldMetadata 94 oldBytes, _ = proto.Marshal(oldMetadata) 95 newChannel = false 96 }) 97 98 It("fails when new consensus metadata has invalid options", func() { 99 // NOTE: we are not checking all failures here since tests for CheckConfigMetadata does that 100 newMetadata.Options.TickInterval = "" 101 newBytes, _ := proto.Marshal(newMetadata) 102 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 103 }) 104 105 Context("new channel creation", func() { 106 107 BeforeEach(func() { 108 newChannel = true 109 }) 110 111 It("fails when the new consenters are an empty set", func() { 112 newMetadata.Consenters = []*etcdraftproto.Consenter{} 113 newBytes, _ := proto.Marshal(newMetadata) 114 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 115 }) 116 117 It("succeeds when the new consenters are the same as the existing consenters", func() { 118 newBytes, _ := proto.Marshal(newMetadata) 119 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 120 }) 121 122 It("succeeds when the new consenters are a subset of the existing consenters", func() { 123 newMetadata.Consenters = newMetadata.Consenters[:2] 124 newBytes, _ := proto.Marshal(newMetadata) 125 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 126 }) 127 128 It("fails when the new consenters are not a subset of the existing consenters", func() { 129 newMetadata.Consenters[2].ClientTlsCert = clientTLSCert(tlsCA) 130 newBytes, _ := proto.Marshal(newMetadata) 131 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 132 }) 133 134 }) 135 136 Context("config update on a channel", func() { 137 138 BeforeEach(func() { 139 newChannel = false 140 chain.ActiveNodes.Store([]uint64{1, 2, 3}) 141 }) 142 143 It("fails when the new consenters are an empty set", func() { 144 // NOTE: This also takes care of the case when we remove node from a singleton consenter set 145 newMetadata.Consenters = []*etcdraftproto.Consenter{} 146 newBytes, _ := proto.Marshal(newMetadata) 147 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 148 }) 149 150 It("succeeds when the new consenters are the same as the existing consenters", func() { 151 newBytes, _ := proto.Marshal(newMetadata) 152 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 153 }) 154 155 It("succeeds on addition of a single consenter", func() { 156 newMetadata.Consenters = append(newMetadata.Consenters, &etcdraftproto.Consenter{ 157 Host: "host4", 158 Port: 10004, 159 ClientTlsCert: clientTLSCert(tlsCA), 160 ServerTlsCert: serverTLSCert(tlsCA), 161 }) 162 newBytes, _ := proto.Marshal(newMetadata) 163 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 164 }) 165 166 It("fails on addition of more than one consenter", func() { 167 newMetadata.Consenters = append(newMetadata.Consenters, 168 &etcdraftproto.Consenter{ 169 Host: "host4", 170 Port: 10004, 171 ClientTlsCert: clientTLSCert(tlsCA), 172 ServerTlsCert: serverTLSCert(tlsCA), 173 }, 174 &etcdraftproto.Consenter{ 175 Host: "host5", 176 Port: 10005, 177 ClientTlsCert: clientTLSCert(tlsCA), 178 ServerTlsCert: serverTLSCert(tlsCA), 179 }, 180 ) 181 newBytes, _ := proto.Marshal(newMetadata) 182 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 183 }) 184 185 It("succeeds on removal of a single consenter", func() { 186 newMetadata.Consenters = newMetadata.Consenters[:2] 187 newBytes, _ := proto.Marshal(newMetadata) 188 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 189 }) 190 191 It("fails on removal of more than one consenter", func() { 192 newMetadata.Consenters = newMetadata.Consenters[:1] 193 newBytes, _ := proto.Marshal(newMetadata) 194 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).NotTo(Succeed()) 195 }) 196 197 It("succeeds on rotating certs in case of both addition and removal of a node each to reuse the raft NodeId", func() { 198 newMetadata.Consenters = append(newMetadata.Consenters[:2], &etcdraftproto.Consenter{ 199 Host: "host4", 200 Port: 10004, 201 ClientTlsCert: clientTLSCert(tlsCA), 202 ServerTlsCert: serverTLSCert(tlsCA), 203 }) 204 newBytes, _ := proto.Marshal(newMetadata) 205 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 206 }) 207 208 It("succeeds on removal of inactive node in 2/3 cluster", func() { 209 chain.ActiveNodes.Store([]uint64{1, 2}) 210 newMetadata.Consenters = newMetadata.Consenters[:2] 211 newBytes, _ := proto.Marshal(newMetadata) 212 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To(Succeed()) 213 }) 214 215 It("fails on removal of active node in 2/3 cluster", func() { 216 chain.ActiveNodes.Store([]uint64{1, 2}) 217 newMetadata.Consenters = newMetadata.Consenters[1:] 218 newBytes, _ := proto.Marshal(newMetadata) 219 Expect(chain.ValidateConsensusMetadata(oldBytes, newBytes, newChannel)).To( 220 MatchError("2 out of 3 nodes are alive, configuration will result in quorum loss")) 221 }) 222 }) 223 }) 224 })