go_study/fabric-main/common/channelconfig/util_test.go

359 lines
13 KiB
Go

/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package channelconfig
import (
"bytes"
"fmt"
"io/ioutil"
"testing"
"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric-config/protolator"
cb "github.com/hyperledger/fabric-protos-go/common"
mspprotos "github.com/hyperledger/fabric-protos-go/msp"
ab "github.com/hyperledger/fabric-protos-go/orderer"
"github.com/hyperledger/fabric-protos-go/orderer/etcdraft"
pb "github.com/hyperledger/fabric-protos-go/peer"
"github.com/hyperledger/fabric/bccsp/sw"
"github.com/hyperledger/fabric/common/capabilities"
"github.com/hyperledger/fabric/protoutil"
"github.com/stretchr/testify/require"
)
// The tests in this file are all relatively pointless, as all of this function is exercised
// in the normal startup path and things will break horribly if they are broken.
// There's additionally really nothing to test without simply re-implementing the function
// in the test, which also provides no value. But, not including these produces an artificially
// low code coverage count, so here they are.
func basicTest(t *testing.T, sv *StandardConfigValue) {
require.NotNil(t, sv)
require.NotEmpty(t, sv.Key())
require.NotNil(t, sv.Value())
}
func TestUtilsBasic(t *testing.T) {
basicTest(t, ConsortiumValue("foo"))
basicTest(t, HashingAlgorithmValue())
basicTest(t, BlockDataHashingStructureValue())
basicTest(t, OrdererAddressesValue([]string{"foo:1", "bar:2"}))
basicTest(t, ConsensusTypeValue("foo", []byte("bar")))
basicTest(t, BatchSizeValue(1, 2, 3))
basicTest(t, BatchTimeoutValue("1s"))
basicTest(t, ChannelRestrictionsValue(7))
basicTest(t, MSPValue(&mspprotos.MSPConfig{}))
basicTest(t, CapabilitiesValue(map[string]bool{"foo": true, "bar": false}))
basicTest(t, AnchorPeersValue([]*pb.AnchorPeer{{}, {}}))
basicTest(t, ChannelCreationPolicyValue(&cb.Policy{}))
basicTest(t, ACLValues(map[string]string{"foo": "fooval", "bar": "barval"}))
}
// createCfgBlockWithSupportedCapabilities will create a config block that contains valid capabilities and should be accepted by the peer
func createCfgBlockWithSupportedCapabilities(t *testing.T) *cb.Block {
// Create a config
config := &cb.Config{
Sequence: 0,
ChannelGroup: protoutil.NewConfigGroup(),
}
// construct the config for top group
config.ChannelGroup.Version = 0
config.ChannelGroup.ModPolicy = AdminsPolicyKey
config.ChannelGroup.Values[BlockDataHashingStructureKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.BlockDataHashingStructure{
Width: defaultBlockDataHashingStructureWidth,
}),
ModPolicy: AdminsPolicyKey,
}
topCapabilities := make(map[string]bool)
topCapabilities[capabilities.ChannelV1_1] = true
config.ChannelGroup.Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(topCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[ConsortiumKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.Consortium{
Name: "testConsortium",
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[HashingAlgorithmKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.HashingAlgorithm{
Name: defaultHashingAlgorithm,
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[OrdererAddressesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.OrdererAddresses{
Addresses: []string{"orderer.example.com"},
}),
ModPolicy: AdminsPolicyKey,
}
// construct the config for Application group
config.ChannelGroup.Groups[ApplicationGroupKey] = protoutil.NewConfigGroup()
config.ChannelGroup.Groups[ApplicationGroupKey].Version = 0
config.ChannelGroup.Groups[ApplicationGroupKey].ModPolicy = AdminsPolicyKey
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[ReadersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[WritersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[AdminsPolicyKey] = &cb.ConfigPolicy{}
appCapabilities := make(map[string]bool)
appCapabilities[capabilities.ApplicationV1_1] = true
config.ChannelGroup.Groups[ApplicationGroupKey].Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(appCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
// construct the config for Orderer group
config.ChannelGroup.Groups[OrdererGroupKey] = protoutil.NewConfigGroup()
config.ChannelGroup.Groups[OrdererGroupKey].Version = 0
config.ChannelGroup.Groups[OrdererGroupKey].ModPolicy = AdminsPolicyKey
config.ChannelGroup.Groups[OrdererGroupKey].Policies[ReadersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Policies[WritersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Policies[AdminsPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchSizeKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.BatchSize{
MaxMessageCount: 65535,
AbsoluteMaxBytes: 1024000000,
PreferredMaxBytes: 1024000000,
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchTimeoutKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.BatchTimeout{
Timeout: "2s",
}),
ModPolicy: AdminsPolicyKey,
}
ordererCapabilities := make(map[string]bool)
ordererCapabilities[capabilities.OrdererV1_1] = true
config.ChannelGroup.Groups[OrdererGroupKey].Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(ordererCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Groups[OrdererGroupKey].Values[ConsensusTypeKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.ConsensusType{
Type: "solo",
}),
ModPolicy: AdminsPolicyKey,
}
env := &cb.Envelope{
Payload: protoutil.MarshalOrPanic(&cb.Payload{
Header: &cb.Header{
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
ChannelId: "testChain",
Type: int32(cb.HeaderType_CONFIG),
}),
},
Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{
Config: config,
}),
}),
}
configBlock := &cb.Block{
Data: &cb.BlockData{
Data: [][]byte{[]byte(protoutil.MarshalOrPanic(env))},
},
}
return configBlock
}
// createCfgBlockWithUnSupportedCapabilities will create a config block that contains mismatched capabilities and should be rejected by the peer
func createCfgBlockWithUnsupportedCapabilities(t *testing.T) *cb.Block {
// Create a config
config := &cb.Config{
Sequence: 0,
ChannelGroup: protoutil.NewConfigGroup(),
}
// construct the config for top group
config.ChannelGroup.Version = 0
config.ChannelGroup.ModPolicy = AdminsPolicyKey
config.ChannelGroup.Values[BlockDataHashingStructureKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.BlockDataHashingStructure{
Width: defaultBlockDataHashingStructureWidth,
}),
ModPolicy: AdminsPolicyKey,
}
topCapabilities := make(map[string]bool)
topCapabilities["INCOMPATIBLE_CAPABILITIES"] = true
config.ChannelGroup.Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(topCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[ConsortiumKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.Consortium{
Name: "testConsortium",
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[HashingAlgorithmKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.HashingAlgorithm{
Name: defaultHashingAlgorithm,
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Values[OrdererAddressesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(&cb.OrdererAddresses{
Addresses: []string{"orderer.example.com"},
}),
ModPolicy: AdminsPolicyKey,
}
// construct the config for Application group
config.ChannelGroup.Groups[ApplicationGroupKey] = protoutil.NewConfigGroup()
config.ChannelGroup.Groups[ApplicationGroupKey].Version = 0
config.ChannelGroup.Groups[ApplicationGroupKey].ModPolicy = AdminsPolicyKey
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[ReadersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[WritersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[ApplicationGroupKey].Policies[AdminsPolicyKey] = &cb.ConfigPolicy{}
appCapabilities := make(map[string]bool)
appCapabilities["INCOMPATIBLE_CAPABILITIES"] = true
config.ChannelGroup.Groups[ApplicationGroupKey].Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(appCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
// construct the config for Orderer group
config.ChannelGroup.Groups[OrdererGroupKey] = protoutil.NewConfigGroup()
config.ChannelGroup.Groups[OrdererGroupKey].Version = 0
config.ChannelGroup.Groups[OrdererGroupKey].ModPolicy = AdminsPolicyKey
config.ChannelGroup.Groups[OrdererGroupKey].Policies[ReadersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Policies[WritersPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Policies[AdminsPolicyKey] = &cb.ConfigPolicy{}
config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchSizeKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.BatchSize{
MaxMessageCount: 65535,
AbsoluteMaxBytes: 1024000000,
PreferredMaxBytes: 1024000000,
}),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Groups[OrdererGroupKey].Values[BatchTimeoutKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.BatchTimeout{
Timeout: "2s",
}),
ModPolicy: AdminsPolicyKey,
}
ordererCapabilities := make(map[string]bool)
ordererCapabilities["INCOMPATIBLE_CAPABILITIES"] = true
config.ChannelGroup.Groups[OrdererGroupKey].Values[CapabilitiesKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(CapabilitiesValue(ordererCapabilities).Value()),
ModPolicy: AdminsPolicyKey,
}
config.ChannelGroup.Groups[OrdererGroupKey].Values[ConsensusTypeKey] = &cb.ConfigValue{
Value: protoutil.MarshalOrPanic(
&ab.ConsensusType{
Type: "solo",
}),
ModPolicy: AdminsPolicyKey,
}
env := &cb.Envelope{
Payload: protoutil.MarshalOrPanic(&cb.Payload{
Header: &cb.Header{
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
ChannelId: "testChain",
Type: int32(cb.HeaderType_CONFIG),
}),
},
Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{
Config: config,
}),
}),
}
configBlock := &cb.Block{
Data: &cb.BlockData{
Data: [][]byte{[]byte(protoutil.MarshalOrPanic(env))},
},
}
return configBlock
}
func TestValidateCapabilities(t *testing.T) {
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
require.NoError(t, err)
// Test config block with valid capabilities requirement
cfgBlock := createCfgBlockWithSupportedCapabilities(t)
err = ValidateCapabilities(cfgBlock, cryptoProvider)
require.NoError(t, err)
// Test config block with invalid capabilities requirement
cfgBlock = createCfgBlockWithUnsupportedCapabilities(t)
err = ValidateCapabilities(cfgBlock, cryptoProvider)
require.EqualError(t, err, "Channel capability INCOMPATIBLE_CAPABILITIES is required but not supported")
}
func TestExtractMSPIDsForApplicationOrgs(t *testing.T) {
// load test_configblock.json that contains the application group
// and other properties needed to build channel config and extract MSPIDs
blockData, err := ioutil.ReadFile("testdata/test_configblock.json")
require.NoError(t, err)
block := &cb.Block{}
protolator.DeepUnmarshalJSON(bytes.NewBuffer(blockData), block)
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore())
require.NoError(t, err)
mspids, err := ExtractMSPIDsForApplicationOrgs(block, cryptoProvider)
require.NoError(t, err)
require.ElementsMatch(t, mspids, []string{"Org1MSP", "Org2MSP"})
}
func TestMarshalEtcdRaftMetadata(t *testing.T) {
md := &etcdraft.ConfigMetadata{
Consenters: []*etcdraft.Consenter{
{
Host: "node-1.example.com",
Port: 7050,
ClientTlsCert: []byte("testdata/tls-client-1.pem"),
ServerTlsCert: []byte("testdata/tls-server-1.pem"),
},
{
Host: "node-2.example.com",
Port: 7050,
ClientTlsCert: []byte("testdata/tls-client-2.pem"),
ServerTlsCert: []byte("testdata/tls-server-2.pem"),
},
{
Host: "node-3.example.com",
Port: 7050,
ClientTlsCert: []byte("testdata/tls-client-3.pem"),
ServerTlsCert: []byte("testdata/tls-server-3.pem"),
},
},
}
packed, err := MarshalEtcdRaftMetadata(md)
require.Nil(t, err, "marshalling should succeed")
require.NotNil(t, packed)
packed, err = MarshalEtcdRaftMetadata(md)
require.Nil(t, err, "marshalling should succeed a second time because we did not mutate ourselves")
require.NotNil(t, packed)
unpacked := &etcdraft.ConfigMetadata{}
require.Nil(t, proto.Unmarshal(packed, unpacked), "unmarshalling should succeed")
var outputCerts, inputCerts [3][]byte
for i := range unpacked.GetConsenters() {
outputCerts[i] = []byte(unpacked.GetConsenters()[i].GetClientTlsCert())
inputCerts[i], _ = ioutil.ReadFile(fmt.Sprintf("testdata/tls-client-%d.pem", i+1))
}
for i := 0; i < len(inputCerts)-1; i++ {
require.NotEqual(t, outputCerts[i+1], outputCerts[i], "expected extracted certs to differ from each other")
}
}