191 lines
5.0 KiB
Go
191 lines
5.0 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package channelparticipation_test
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
"testing"
|
|
|
|
"github.com/golang/protobuf/proto"
|
|
cb "github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric/bccsp"
|
|
"github.com/hyperledger/fabric/orderer/common/channelparticipation"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestValidateJoinBlock(t *testing.T) {
|
|
validJoinBlock := blockWithGroups(
|
|
map[string]*cb.ConfigGroup{
|
|
"Application": {},
|
|
},
|
|
"my-channel",
|
|
)
|
|
|
|
tests := []struct {
|
|
testName string
|
|
joinBlock *cb.Block
|
|
expectedChannelID string
|
|
expectedErr error
|
|
}{
|
|
{
|
|
testName: "Valid application channel join block",
|
|
joinBlock: validJoinBlock,
|
|
expectedChannelID: "my-channel",
|
|
expectedErr: nil,
|
|
},
|
|
{
|
|
testName: "Invalid block data hash",
|
|
joinBlock: func() *cb.Block {
|
|
b := proto.Clone(validJoinBlock).(*cb.Block)
|
|
b.Header.DataHash = []byte("bogus")
|
|
return b
|
|
}(),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("invalid block: Header.DataHash is different from Hash(block.Data)"),
|
|
},
|
|
{
|
|
testName: "Invalid block metadata",
|
|
joinBlock: func() *cb.Block {
|
|
b := proto.Clone(validJoinBlock).(*cb.Block)
|
|
b.Metadata = nil
|
|
return b
|
|
}(),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("invalid block: does not have metadata"),
|
|
},
|
|
{
|
|
testName: "Not supported: system channel join block",
|
|
joinBlock: blockWithGroups(
|
|
map[string]*cb.ConfigGroup{
|
|
"Consortiums": {},
|
|
},
|
|
"my-channel",
|
|
),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("invalid config: contains consortiums: system channel not supported"),
|
|
},
|
|
{
|
|
testName: "Join block not a config block",
|
|
joinBlock: nonConfigBlock(),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("block is not a config block"),
|
|
},
|
|
{
|
|
testName: "block ChannelID not valid",
|
|
joinBlock: blockWithGroups(
|
|
map[string]*cb.ConfigGroup{
|
|
"Consortiums": {},
|
|
},
|
|
"My-Channel",
|
|
),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("initializing configtx manager failed: bad channel ID: 'My-Channel' contains illegal characters"),
|
|
},
|
|
{
|
|
testName: "Invalid bundle",
|
|
joinBlock: blockWithGroups(
|
|
map[string]*cb.ConfigGroup{
|
|
"InvalidGroup": {},
|
|
},
|
|
"my-channel",
|
|
),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("initializing channelconfig failed: Disallowed channel group: "),
|
|
},
|
|
{
|
|
testName: "Join block has no application or consortiums group",
|
|
joinBlock: blockWithGroups(
|
|
map[string]*cb.ConfigGroup{},
|
|
"my-channel",
|
|
),
|
|
expectedChannelID: "",
|
|
expectedErr: errors.New("invalid config: must contain application config"),
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.testName, func(t *testing.T) {
|
|
channelID, err := channelparticipation.ValidateJoinBlock(test.joinBlock)
|
|
require.Equal(t, test.expectedChannelID, channelID)
|
|
if test.expectedErr != nil {
|
|
require.EqualError(t, err, test.expectedErr.Error())
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func blockWithGroups(groups map[string]*cb.ConfigGroup, channelID string) *cb.Block {
|
|
block := protoutil.NewBlock(0, []byte{})
|
|
block.Data = &cb.BlockData{
|
|
Data: [][]byte{
|
|
protoutil.MarshalOrPanic(&cb.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(&cb.Payload{
|
|
Data: protoutil.MarshalOrPanic(&cb.ConfigEnvelope{
|
|
Config: &cb.Config{
|
|
ChannelGroup: &cb.ConfigGroup{
|
|
Groups: groups,
|
|
Values: map[string]*cb.ConfigValue{
|
|
"HashingAlgorithm": {
|
|
Value: protoutil.MarshalOrPanic(&cb.HashingAlgorithm{
|
|
Name: bccsp.SHA256,
|
|
}),
|
|
},
|
|
"BlockDataHashingStructure": {
|
|
Value: protoutil.MarshalOrPanic(&cb.BlockDataHashingStructure{
|
|
Width: math.MaxUint32,
|
|
}),
|
|
},
|
|
"OrdererAddresses": {
|
|
Value: protoutil.MarshalOrPanic(&cb.OrdererAddresses{
|
|
Addresses: []string{"localhost"},
|
|
}),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
Header: &cb.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
|
|
Type: int32(cb.HeaderType_CONFIG),
|
|
ChannelId: channelID,
|
|
}),
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
}
|
|
block.Header.DataHash = protoutil.BlockDataHash(block.Data)
|
|
protoutil.InitBlockMetadata(block)
|
|
|
|
return block
|
|
}
|
|
|
|
func nonConfigBlock() *cb.Block {
|
|
block := protoutil.NewBlock(0, []byte{})
|
|
block.Data = &cb.BlockData{
|
|
Data: [][]byte{
|
|
protoutil.MarshalOrPanic(&cb.Envelope{
|
|
Payload: protoutil.MarshalOrPanic(&cb.Payload{
|
|
Header: &cb.Header{
|
|
ChannelHeader: protoutil.MarshalOrPanic(&cb.ChannelHeader{
|
|
Type: int32(cb.HeaderType_ENDORSER_TRANSACTION),
|
|
}),
|
|
},
|
|
}),
|
|
}),
|
|
},
|
|
}
|
|
block.Header.DataHash = protoutil.BlockDataHash(block.Data)
|
|
protoutil.InitBlockMetadata(block)
|
|
|
|
return block
|
|
}
|