-
Notifications
You must be signed in to change notification settings - Fork 8.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FAB-17963] Ch.Part.API: Validate join block (#1393)
* Introduce function for validating the join block received by channel participation rest API. `ValidateJoinBlock` will determine whether the block contains an application channel or system channel and does basic validation on the structure of the join block. Signed-off-by: Danny Cao <dcao@us.ibm.com>
- Loading branch information
Showing
7 changed files
with
264 additions
and
17 deletions.
There are no files selected for viewing
18 changes: 10 additions & 8 deletions
18
orderer/common/channelparticipation/mocks/channel_management.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package channelparticipation | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
cb "github.com/hyperledger/fabric-protos-go/common" | ||
"github.com/hyperledger/fabric/bccsp/factory" | ||
"github.com/hyperledger/fabric/common/channelconfig" | ||
"github.com/hyperledger/fabric/protoutil" | ||
) | ||
|
||
// ValidateJoinBlock returns whether this block can be used as a join block for the channel participation API | ||
// and whether it is an system channel if it contains consortiums, or otherwise | ||
// and application channel if an application group exists. | ||
func ValidateJoinBlock(channelID string, configBlock *cb.Block) (isAppChannel bool, err error) { | ||
if !protoutil.IsConfigBlock(configBlock) { | ||
return false, errors.New("block is not a config block") | ||
} | ||
|
||
envelope, err := protoutil.ExtractEnvelope(configBlock, 0) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
cryptoProvider := factory.GetDefault() | ||
bundle, err := channelconfig.NewBundleFromEnvelope(envelope, cryptoProvider) | ||
if err != nil { | ||
return false, err | ||
} | ||
|
||
// Check channel id from join block matches | ||
if bundle.ConfigtxValidator().ChannelID() != channelID { | ||
return false, fmt.Errorf("config block channelID [%s] does not match passed channelID [%s]", | ||
bundle.ConfigtxValidator().ChannelID(), channelID) | ||
} | ||
|
||
// Check channel type | ||
_, isSystemChannel := bundle.ConsortiumsConfig() | ||
if !isSystemChannel { | ||
_, isAppChannel = bundle.ApplicationConfig() | ||
if !isAppChannel { | ||
return false, errors.New("invalid config: must have at least one of application or consortiums") | ||
} | ||
} | ||
|
||
return isAppChannel, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
Copyright IBM Corp. All Rights Reserved. | ||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package channelparticipation_test | ||
|
||
import ( | ||
"errors" | ||
"math" | ||
"testing" | ||
|
||
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/assert" | ||
) | ||
|
||
func TestValidateJoinBlock(t *testing.T) { | ||
tests := []struct { | ||
testName string | ||
channelID string | ||
joinBlock *cb.Block | ||
expectedIsAppChannel bool | ||
expectedErr error | ||
}{ | ||
{ | ||
testName: "Valid system channel join block", | ||
channelID: "my-channel", | ||
joinBlock: blockWithGroups( | ||
map[string]*cb.ConfigGroup{ | ||
"Consortiums": {}, | ||
}, | ||
"my-channel", | ||
), | ||
expectedIsAppChannel: false, | ||
expectedErr: nil, | ||
}, | ||
{ | ||
testName: "Valid application channel join block", | ||
channelID: "my-channel", | ||
joinBlock: blockWithGroups( | ||
map[string]*cb.ConfigGroup{ | ||
"Application": {}, | ||
}, | ||
"my-channel", | ||
), | ||
expectedIsAppChannel: true, | ||
expectedErr: nil, | ||
}, | ||
{ | ||
testName: "Join block not a config block", | ||
channelID: "my-channel", | ||
joinBlock: nonConfigBlock(), | ||
expectedIsAppChannel: false, | ||
expectedErr: errors.New("block is not a config block"), | ||
}, | ||
{ | ||
testName: "ChannelID does not match join blocks", | ||
channelID: "not-my-channel", | ||
joinBlock: blockWithGroups( | ||
map[string]*cb.ConfigGroup{ | ||
"Consortiums": {}, | ||
}, | ||
"my-channel", | ||
), | ||
expectedIsAppChannel: false, | ||
expectedErr: errors.New("config block channelID [my-channel] does not match passed channelID [not-my-channel]"), | ||
}, | ||
{ | ||
testName: "Invalid bundle", | ||
channelID: "my-channel", | ||
joinBlock: blockWithGroups( | ||
map[string]*cb.ConfigGroup{ | ||
"InvalidGroup": {}, | ||
}, | ||
"my-channel", | ||
), | ||
expectedIsAppChannel: false, | ||
expectedErr: nil, | ||
}, | ||
{ | ||
testName: "Join block has no application or consortiums group", | ||
channelID: "my-channel", | ||
joinBlock: blockWithGroups( | ||
map[string]*cb.ConfigGroup{}, | ||
"my-channel", | ||
), | ||
expectedIsAppChannel: false, | ||
expectedErr: errors.New("invalid config: must have at least one of application or consortiums"), | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.testName, func(t *testing.T) { | ||
isAppChannel, err := channelparticipation.ValidateJoinBlock(test.channelID, test.joinBlock) | ||
assert.Equal(t, isAppChannel, test.expectedIsAppChannel) | ||
if test.expectedErr != nil { | ||
assert.EqualError(t, err, test.expectedErr.Error()) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func blockWithGroups(groups map[string]*cb.ConfigGroup, channelID string) *cb.Block { | ||
return &cb.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, | ||
}), | ||
}, | ||
}), | ||
}), | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func nonConfigBlock() *cb.Block { | ||
return &cb.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), | ||
}), | ||
}, | ||
}), | ||
}), | ||
}, | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.