@@ -27,9 +27,9 @@ import (
27
27
"os"
28
28
"time"
29
29
30
- "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
31
-
30
+ "github.com/golang/protobuf/proto"
32
31
"github.com/hyperledger/fabric-sdk-go/pkg/client/common/verifier"
32
+ "github.com/hyperledger/fabric-sdk-go/pkg/common/errors/retry"
33
33
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
34
34
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/msp"
35
35
"github.com/hyperledger/fabric-sdk-go/pkg/fab/channel"
@@ -48,6 +48,8 @@ import (
48
48
"github.com/pkg/errors"
49
49
)
50
50
51
+ const bufferSize = 1024
52
+
51
53
// InstallCCRequest contains install chaincode request parameters
52
54
type InstallCCRequest struct {
53
55
Name string
@@ -101,6 +103,8 @@ type requestOptions struct {
101
103
Timeouts map [fab.TimeoutType ]time.Duration //timeout options for resmgmt operations
102
104
ParentContext reqContext.Context //parent grpc context for resmgmt operations
103
105
Retry retry.Opts
106
+ // signatures for channel configurations, if set, this option will take precedence over signatures of SaveChannelRequest.SigningIdentities
107
+ Signatures []* common.ConfigSignature
104
108
}
105
109
106
110
//SaveChannelRequest holds parameters for save channel request
@@ -109,7 +113,6 @@ type SaveChannelRequest struct {
109
113
ChannelConfig io.Reader // ChannelConfig data source
110
114
ChannelConfigPath string // Convenience option to use the named file as ChannelConfig reader
111
115
SigningIdentities []msp.SigningIdentity // Users that sign channel configuration
112
- // TODO: support pre-signed signature blocks
113
116
}
114
117
115
118
// SaveChannelResponse contains response parameters for save channel
@@ -832,6 +835,9 @@ func peersToTxnProcessors(peers []fab.Peer) []fab.ProposalProcessor {
832
835
// Parameters:
833
836
// req holds info about mandatory channel name and configuration
834
837
// options holds optional request options
838
+ // if options have signatures (WithConfigSignatures() or 1 or more WithConfigSignature() calls), then SaveChannel will
839
+ // use these signatures instead of creating ones for the SigningIdentities found in req.
840
+ // Make sure that req.ChannelConfigPath/req.ChannelConfig have the channel config matching these signatures.
835
841
//
836
842
// Returns:
837
843
// save channel response with transaction ID
@@ -858,24 +864,24 @@ func (rc *Client) SaveChannel(req SaveChannelRequest, options ...RequestOption)
858
864
859
865
logger .Debugf ("saving channel: %s" , req .ChannelID )
860
866
861
- configTx , err := ioutil . ReadAll (req .ChannelConfig )
867
+ chConfig , err := extractChConfigData (req .ChannelConfig )
862
868
if err != nil {
863
- return SaveChannelResponse {}, errors .WithMessage (err , "reading channel config file failed" )
864
- }
865
-
866
- chConfig , err := resource .ExtractChannelConfig (configTx )
867
- if err != nil {
868
- return SaveChannelResponse {}, errors .WithMessage (err , "extracting channel config failed" )
869
+ return SaveChannelResponse {}, errors .WithMessage (err , "extracting channel config from ConfigTx failed" )
869
870
}
870
871
871
872
orderer , err := rc .requestOrderer (& opts , req .ChannelID )
872
873
if err != nil {
873
874
return SaveChannelResponse {}, errors .WithMessage (err , "failed to find orderer for request" )
874
875
}
875
876
876
- configSignatures , err := rc .getConfigSignatures (req , chConfig )
877
- if err != nil {
878
- return SaveChannelResponse {}, err
877
+ var configSignatures []* common.ConfigSignature
878
+ if opts .Signatures != nil {
879
+ configSignatures = opts .Signatures
880
+ } else {
881
+ configSignatures , err = rc .getConfigSignatures (req , chConfig )
882
+ if err != nil {
883
+ return SaveChannelResponse {}, err
884
+ }
879
885
}
880
886
881
887
request := resource.CreateChannelRequest {
@@ -905,7 +911,6 @@ func (rc *Client) validateSaveChannelRequest(req SaveChannelRequest) error {
905
911
}
906
912
907
913
func (rc * Client ) getConfigSignatures (req SaveChannelRequest , chConfig []byte ) ([]* common.ConfigSignature , error ) {
908
-
909
914
// Signing user has to belong to one of configured channel organisations
910
915
// In case that order org is one of channel orgs we can use context user
911
916
var signers []msp.SigningIdentity
@@ -922,6 +927,150 @@ func (rc *Client) getConfigSignatures(req SaveChannelRequest, chConfig []byte) (
922
927
return nil , errors .New ("must provide signing user" )
923
928
}
924
929
930
+ return rc .createCfgSigFromIDs (chConfig , signers ... )
931
+ }
932
+
933
+ func readChConfigData (channelConfigPath string ) ([]byte , error ) {
934
+ if channelConfigPath == "" {
935
+ return nil , errors .New ("must provide a channel config path" )
936
+ }
937
+
938
+ configReader , err := os .Open (channelConfigPath ) // nolint
939
+ if err != nil {
940
+ return nil , errors .Wrapf (err , "opening channel config file failed" )
941
+ }
942
+ defer loggedClose (configReader )
943
+
944
+ chConfig , err := extractChConfigData (configReader )
945
+ if err != nil {
946
+ return nil , errors .WithMessage (err , "extracting channel config from channel config reader of channelConfigPath failed" )
947
+ }
948
+ return chConfig , nil
949
+ }
950
+
951
+ func extractChConfigData (channelConfigReader io.Reader ) ([]byte , error ) {
952
+ if channelConfigReader == nil {
953
+ return nil , errors .New ("must provide a non empty channel config file" )
954
+ }
955
+ configTx , err := ioutil .ReadAll (channelConfigReader )
956
+ if err != nil {
957
+ return nil , errors .WithMessage (err , "reading channel config file failed" )
958
+ }
959
+
960
+ chConfig , err := resource .ExtractChannelConfig (configTx )
961
+ if err != nil {
962
+ return nil , errors .WithMessage (err , "extracting channel config from ConfigTx failed" )
963
+ }
964
+
965
+ return chConfig , nil
966
+ }
967
+
968
+ // CreateConfigSignature creates a signature for the given client, custom signers and chConfig from channelConfigPath argument
969
+ // return ConfigSignature will be signed internally by the SDK. It can be passed to WithConfigSignatures() option
970
+ func (rc * Client ) CreateConfigSignature (signer msp.SigningIdentity , channelConfigPath string ) (* common.ConfigSignature , error ) {
971
+ chConfig , err := readChConfigData (channelConfigPath )
972
+ if err != nil {
973
+ return nil , err
974
+ }
975
+
976
+ sigs , err := rc .createCfgSigFromIDs (chConfig , signer )
977
+ if err != nil {
978
+ return nil , err
979
+ }
980
+
981
+ if len (sigs ) != 1 {
982
+ return nil , errors .New ("creating a config signature for 1 identity did not return 1 signature" )
983
+ }
984
+
985
+ return sigs [0 ], nil
986
+ }
987
+
988
+ // CreateConfigSignatureData will prepare a SignatureHeader and the full signing []byte (signingBytes) to be used for signing a Channel Config
989
+ // Once SigningBytes have been signed externally (signing signatureHeaderData.SigningBytes using an external tool like OpenSSL), do the following:
990
+ // 1. create a common.ConfigSignature{} instance
991
+ // 2. assign its SignatureHeader field with the returned field 'signatureHeaderData.signatureHeader'
992
+ // 3. assign its Signature field with the generated signature of 'signatureHeaderData.signingBytes' from the external tool
993
+ // Then use WithConfigSignatures() option to pass this new instance for channel updates
994
+ func (rc * Client ) CreateConfigSignatureData (signer msp.SigningIdentity , channelConfigPath string ) (signatureHeaderData resource.ConfigSignatureData , e error ) {
995
+ chConfig , err := readChConfigData (channelConfigPath )
996
+ if err != nil {
997
+ e = err
998
+ return
999
+ }
1000
+ sigCtx := contextImpl.Client {
1001
+ SigningIdentity : signer ,
1002
+ Providers : rc .ctx ,
1003
+ }
1004
+
1005
+ return resource .GetConfigSignatureData (& sigCtx , chConfig )
1006
+ }
1007
+
1008
+ // MarshalConfigSignature marshals 1 ConfigSignature for the given client concatenated as []byte
1009
+ func MarshalConfigSignature (signature * common.ConfigSignature ) ([]byte , error ) {
1010
+ mSig , err := proto .Marshal (signature )
1011
+ if err != nil {
1012
+ return nil , errors .WithMessage (err , "failed to marshal signature" )
1013
+ }
1014
+ return mSig , nil
1015
+ }
1016
+
1017
+ // UnmarshalConfigSignature reads 1 ConfigSignature as []byte from reader and unmarshals it
1018
+ func UnmarshalConfigSignature (reader io.Reader ) (* common.ConfigSignature , error ) {
1019
+ arr , err := readConfigSignatureArray (reader )
1020
+ if err != nil {
1021
+ return nil , errors .Wrap (err , "reading ConfigSiganture array failed" )
1022
+ }
1023
+
1024
+ configSignature := & common.ConfigSignature {}
1025
+ err = proto .Unmarshal (arr , configSignature )
1026
+ if err != nil {
1027
+ return nil , errors .WithMessage (err , "Failed to unmarshal config signature" )
1028
+ }
1029
+ return configSignature , nil
1030
+ }
1031
+
1032
+ func createConfigSignatureOption (r io.Reader , opts * requestOptions ) error {
1033
+ arr , err := readConfigSignatureArray (r )
1034
+ if err != nil {
1035
+ logger .Warnf ("Failed to read channel config signature from bytes array: %s .. ignoring" , err )
1036
+ return err
1037
+ }
1038
+
1039
+ singleSig := & common.ConfigSignature {}
1040
+
1041
+ err = proto .Unmarshal (arr , singleSig )
1042
+ if err != nil {
1043
+ logger .Warnf ("Failed to unmarshal channel config signature from bytes array: %s .. ignoring signature" , err )
1044
+ return err
1045
+ }
1046
+
1047
+ opts .Signatures = append (opts .Signatures , singleSig )
1048
+
1049
+ return nil
1050
+ }
1051
+
1052
+ func readConfigSignatureArray (reader io.Reader ) ([]byte , error ) {
1053
+ buff := make ([]byte , bufferSize )
1054
+ arr := []byte {}
1055
+ for {
1056
+ n , err := reader .Read (buff )
1057
+ if err != nil && err != io .EOF {
1058
+ logger .Warnf ("Failed to read config signature data from reader: %s" , err )
1059
+ return nil , errors .WithMessage (err , "Failed to read config signature data from reader" )
1060
+ }
1061
+
1062
+ if n == 0 {
1063
+ break
1064
+ } else if n < bufferSize {
1065
+ arr = append (arr , buff [:n ]... )
1066
+ } else {
1067
+ arr = append (arr , buff ... )
1068
+ }
1069
+ }
1070
+ return arr , nil
1071
+ }
1072
+
1073
+ func (rc * Client ) createCfgSigFromIDs (chConfig []byte , signers ... msp.SigningIdentity ) ([]* common.ConfigSignature , error ) {
925
1074
var configSignatures []* common.ConfigSignature
926
1075
for _ , signer := range signers {
927
1076
@@ -938,7 +1087,6 @@ func (rc *Client) getConfigSignatures(req SaveChannelRequest, chConfig []byte) (
938
1087
}
939
1088
940
1089
return configSignatures , nil
941
-
942
1090
}
943
1091
944
1092
func loggedClose (c io.Closer ) {
0 commit comments