github.com/defanghe/fabric@v2.1.1+incompatible/orderer/consensus/etcdraft/util_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package etcdraft 8 9 import ( 10 "encoding/base64" 11 "io/ioutil" 12 "path/filepath" 13 "testing" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-protos-go/common" 17 etcdraftproto "github.com/hyperledger/fabric-protos-go/orderer/etcdraft" 18 "github.com/hyperledger/fabric/bccsp/sw" 19 "github.com/hyperledger/fabric/common/crypto/tlsgen" 20 "github.com/hyperledger/fabric/orderer/common/cluster" 21 "github.com/hyperledger/fabric/protoutil" 22 "github.com/stretchr/testify/assert" 23 ) 24 25 func TestIsConsenterOfChannel(t *testing.T) { 26 certInsideConfigBlock, err := base64.StdEncoding.DecodeString("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNmekNDQWlhZ0F3SUJBZ0l" + 27 "SQUo4bjFLYTVzS1ZaTXRMTHJ1dldERDB3Q2dZSUtvWkl6ajBFQXdJd2JERUwKTUFrR0ExVUVCaE1DVlZNeEV6QVJCZ05WQkFnVENrTmhiR" + 28 "2xtYjNKdWFXRXhGakFVQmdOVkJBY1REVk5oYmlCRwpjbUZ1WTJselkyOHhGREFTQmdOVkJBb1RDMlY0WVcxd2JHVXVZMjl0TVJvd0dBWUR" + 29 "WUVFERXhGMGJITmpZUzVsCmVHRnRjR3hsTG1OdmJUQWVGdzB4T0RFeE1EWXdPVFE1TURCYUZ3MHlPREV4TURNd09UUTVNREJhTUZreEN6QU" + 30 "oKQmdOVkJBWVRBbFZUTVJNd0VRWURWUVFJRXdwRFlXeHBabTl5Ym1saE1SWXdGQVlEVlFRSEV3MVRZVzRnUm5KaApibU5wYzJOdk1SMHdH" + 31 "d1lEVlFRREV4UnZjbVJsY21WeU1TNWxlR0Z0Y0d4bExtTnZiVEJaTUJNR0J5cUdTTTQ5CkFnRUdDQ3FHU000OUF3RUhBMElBQkRUVlFZc0" + 32 "ZKZWxUcFZDMDFsek5DSkx6OENRMFFGVDBvN1BmSnBwSkl2SXgKUCtRVjQvRGRCSnRqQ0cvcGsvMGFxZXRpSjhZRUFMYmMrOUhmWnExN2tJ" + 33 "Q2pnYnN3Z2Jnd0RnWURWUjBQQVFILwpCQVFEQWdXZ01CMEdBMVVkSlFRV01CUUdDQ3NHQVFVRkJ3TUJCZ2dyQmdFRkJRY0RBakFNQmdOV" + 34 "khSTUJBZjhFCkFqQUFNQ3NHQTFVZEl3UWtNQ0tBSUVBOHFrSVJRTVBuWkxBR2g0TXZla2gzZFpHTmNxcEhZZWlXdzE3Rmw0ZlMKTUV3R0" + 35 "ExVWRFUVJGTUVPQ0ZHOXlaR1Z5WlhJeExtVjRZVzF3YkdVdVkyOXRnZ2h2Y21SbGNtVnlNWUlKYkc5agpZV3hvYjNOMGh3Ui9BQUFCaHh" + 36 "BQUFBQUFBQUFBQUFBQUFBQUFBQUFCTUFvR0NDcUdTTTQ5QkFNQ0EwY0FNRVFDCklFckJZRFVzV0JwOHB0ZVFSaTZyNjNVelhJQi81Sn" + 37 "YxK0RlTkRIUHc3aDljQWlCakYrM3V5TzBvMEdRclB4MEUKUWptYlI5T3BVREN2LzlEUkNXWU9GZitkVlE9PQotLS0tLUVORCBDRVJUSU" + 38 "ZJQ0FURS0tLS0tCg==") 39 assert.NoError(t, err) 40 41 validBlock := func() *common.Block { 42 b, err := ioutil.ReadFile(filepath.Join("testdata", "etcdraftgenesis.block")) 43 assert.NoError(t, err) 44 block := &common.Block{} 45 err = proto.Unmarshal(b, block) 46 assert.NoError(t, err) 47 return block 48 } 49 for _, testCase := range []struct { 50 name string 51 expectedError string 52 configBlock *common.Block 53 certificate []byte 54 }{ 55 { 56 name: "nil block", 57 expectedError: "nil block", 58 }, 59 { 60 name: "no block data", 61 expectedError: "block data is nil", 62 configBlock: &common.Block{}, 63 }, 64 { 65 name: "invalid envelope inside block", 66 expectedError: "failed to unmarshal payload from envelope:" + 67 " error unmarshaling Payload: proto: common.Payload: illegal tag 0 (wire type 1)", 68 configBlock: &common.Block{ 69 Data: &common.BlockData{ 70 Data: [][]byte{protoutil.MarshalOrPanic(&common.Envelope{ 71 Payload: []byte{1, 2, 3}, 72 })}, 73 }, 74 }, 75 }, 76 { 77 name: "valid config block with cert mismatch", 78 configBlock: validBlock(), 79 certificate: certInsideConfigBlock[2:], 80 expectedError: cluster.ErrNotInChannel.Error(), 81 }, 82 { 83 name: "valid config block with matching cert", 84 configBlock: validBlock(), 85 certificate: certInsideConfigBlock, 86 }, 87 } { 88 t.Run(testCase.name, func(t *testing.T) { 89 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 90 assert.NoError(t, err) 91 92 consenterCertificate := &ConsenterCertificate{ 93 ConsenterCertificate: testCase.certificate, 94 CryptoProvider: cryptoProvider, 95 } 96 err = consenterCertificate.IsConsenterOfChannel(testCase.configBlock) 97 if testCase.expectedError != "" { 98 assert.EqualError(t, err, testCase.expectedError) 99 } else { 100 assert.NoError(t, err) 101 } 102 }) 103 } 104 } 105 106 func TestCheckConfigMetadata(t *testing.T) { 107 tlsCA, err := tlsgen.NewCA() 108 if err != nil { 109 panic(err) 110 } 111 serverPair, err := tlsCA.NewServerCertKeyPair("localhost") 112 serverCert := serverPair.Cert 113 if err != nil { 114 panic(err) 115 } 116 clientPair, err := tlsCA.NewClientCertKeyPair() 117 clientCert := clientPair.Cert 118 if err != nil { 119 panic(err) 120 } 121 validOptions := &etcdraftproto.Options{ 122 TickInterval: "500ms", 123 ElectionTick: 10, 124 HeartbeatTick: 1, 125 MaxInflightBlocks: 5, 126 SnapshotIntervalSize: 20 * 1024 * 1024, // 20 MB 127 } 128 singleConsenter := &etcdraftproto.Consenter{ 129 Host: "host1", 130 Port: 10001, 131 ClientTlsCert: clientCert, 132 ServerTlsCert: serverCert, 133 } 134 135 // valid metadata should give nil error 136 goodMetadata := &etcdraftproto.ConfigMetadata{ 137 Options: validOptions, 138 Consenters: []*etcdraftproto.Consenter{ 139 singleConsenter, 140 }, 141 } 142 assert.Nil(t, CheckConfigMetadata(goodMetadata)) 143 144 // test variety of bad metadata 145 for _, testCase := range []struct { 146 description string 147 metadata *etcdraftproto.ConfigMetadata 148 errRegex string 149 }{ 150 { 151 description: "nil metadata", 152 metadata: nil, 153 errRegex: "nil Raft config metadata", 154 }, 155 { 156 description: "nil options", 157 metadata: &etcdraftproto.ConfigMetadata{}, 158 errRegex: "nil Raft config metadata options", 159 }, 160 { 161 description: "HeartbeatTick is 0", 162 metadata: &etcdraftproto.ConfigMetadata{ 163 Options: &etcdraftproto.Options{ 164 HeartbeatTick: 0, 165 }, 166 }, 167 errRegex: "none of HeartbeatTick .* can be zero", 168 }, 169 { 170 description: "ElectionTick is 0", 171 metadata: &etcdraftproto.ConfigMetadata{ 172 Options: &etcdraftproto.Options{ 173 HeartbeatTick: validOptions.HeartbeatTick, 174 ElectionTick: 0, 175 }, 176 }, 177 errRegex: "none of .* ElectionTick .* can be zero", 178 }, 179 { 180 description: "MaxInflightBlocks is 0", 181 metadata: &etcdraftproto.ConfigMetadata{ 182 Options: &etcdraftproto.Options{ 183 HeartbeatTick: validOptions.HeartbeatTick, 184 ElectionTick: validOptions.ElectionTick, 185 MaxInflightBlocks: 0, 186 }, 187 }, 188 errRegex: "none of .* MaxInflightBlocks .* can be zero", 189 }, 190 { 191 description: "ElectionTick is less than HeartbeatTick", 192 metadata: &etcdraftproto.ConfigMetadata{ 193 Options: &etcdraftproto.Options{ 194 HeartbeatTick: 10, 195 ElectionTick: 1, 196 MaxInflightBlocks: validOptions.MaxInflightBlocks, 197 }, 198 }, 199 errRegex: "ElectionTick .* must be greater than HeartbeatTick", 200 }, 201 { 202 description: "TickInterval is not parsable", 203 metadata: &etcdraftproto.ConfigMetadata{ 204 Options: &etcdraftproto.Options{ 205 HeartbeatTick: validOptions.HeartbeatTick, 206 ElectionTick: validOptions.ElectionTick, 207 MaxInflightBlocks: validOptions.MaxInflightBlocks, 208 TickInterval: "abcd", 209 }, 210 }, 211 errRegex: "failed to parse TickInterval .* to time duration", 212 }, 213 { 214 description: "TickInterval is 0", 215 metadata: &etcdraftproto.ConfigMetadata{ 216 Options: &etcdraftproto.Options{ 217 HeartbeatTick: validOptions.HeartbeatTick, 218 ElectionTick: validOptions.ElectionTick, 219 MaxInflightBlocks: validOptions.MaxInflightBlocks, 220 TickInterval: "0s", 221 }, 222 }, 223 errRegex: "TickInterval cannot be zero", 224 }, 225 { 226 description: "consenter set is empty", 227 metadata: &etcdraftproto.ConfigMetadata{ 228 Options: validOptions, 229 Consenters: []*etcdraftproto.Consenter{}, 230 }, 231 errRegex: "empty consenter set", 232 }, 233 { 234 description: "metadata has nil consenter", 235 metadata: &etcdraftproto.ConfigMetadata{ 236 Options: validOptions, 237 Consenters: []*etcdraftproto.Consenter{ 238 nil, 239 }, 240 }, 241 errRegex: "metadata has nil consenter", 242 }, 243 { 244 description: "consenter has invalid server cert", 245 metadata: &etcdraftproto.ConfigMetadata{ 246 Options: validOptions, 247 Consenters: []*etcdraftproto.Consenter{ 248 { 249 ServerTlsCert: []byte("invalid"), 250 ClientTlsCert: clientCert, 251 }, 252 }, 253 }, 254 errRegex: "server TLS certificate is not PEM encoded", 255 }, 256 { 257 description: "consenter has invalid client cert", 258 metadata: &etcdraftproto.ConfigMetadata{ 259 Options: validOptions, 260 Consenters: []*etcdraftproto.Consenter{ 261 { 262 ServerTlsCert: serverCert, 263 ClientTlsCert: []byte("invalid"), 264 }, 265 }, 266 }, 267 errRegex: "client TLS certificate is not PEM encoded", 268 }, 269 { 270 description: "metadata has duplicate consenters", 271 metadata: &etcdraftproto.ConfigMetadata{ 272 Options: validOptions, 273 Consenters: []*etcdraftproto.Consenter{ 274 singleConsenter, 275 singleConsenter, 276 }, 277 }, 278 errRegex: "duplicate consenter", 279 }, 280 } { 281 err := CheckConfigMetadata(testCase.metadata) 282 assert.NotNil(t, err, testCase.description) 283 assert.Regexp(t, testCase.errRegex, err) 284 } 285 }