From d0aa67d6b386f3471ec4de10815d34d45c2a9efa Mon Sep 17 00:00:00 2001 From: Artem Barger Date: Thu, 28 Dec 2023 02:02:40 +0200 Subject: [PATCH] Remove chaincode legacy cli command This commit is to remove peer cli chaincode command to get rid of deprecated chaincode lifecycle. Signed-off-by: Artem Barger --- cmd/peer/main.go | 2 - internal/peer/chaincode/chaincode.go | 157 --- internal/peer/chaincode/common.go | 890 ------------------ internal/peer/chaincode/common_test.go | 841 ----------------- internal/peer/chaincode/flags_test.go | 68 -- internal/peer/chaincode/install.go | 278 ------ internal/peer/chaincode/install_test.go | 152 --- internal/peer/chaincode/instantiate.go | 132 --- internal/peer/chaincode/instantiate_test.go | 90 -- internal/peer/chaincode/invoke.go | 63 -- internal/peer/chaincode/invoke_test.go | 411 -------- internal/peer/chaincode/list.go | 170 ---- internal/peer/chaincode/list_test.go | 176 ---- internal/peer/chaincode/mock/deliver.go | 587 ------------ .../peer/chaincode/mock/deliver_client.go | 277 ------ .../peer/chaincode/mock/signer_serializer.go | 185 ---- internal/peer/chaincode/package.go | 225 ----- internal/peer/chaincode/package_test.go | 213 ----- internal/peer/chaincode/query.go | 64 -- internal/peer/chaincode/query_test.go | 103 -- internal/peer/chaincode/signpackage.go | 70 -- internal/peer/chaincode/signpackage_test.go | 131 --- .../testdata/connectionprofile-uneven.yaml | 184 ---- .../chaincode/testdata/connectionprofile.yaml | 184 ---- .../testdata/src/chaincodes/noop/chaincode.go | 32 - internal/peer/chaincode/upgrade.go | 135 --- internal/peer/chaincode/upgrade_test.go | 171 ---- .../lifecycle/chaincode/approveformyorg.go | 5 +- internal/peer/lifecycle/chaincode/commit.go | 5 +- internal/peer/lifecycle/chaincode/common.go | 375 +++++++- 30 files changed, 377 insertions(+), 5999 deletions(-) delete mode 100644 internal/peer/chaincode/chaincode.go delete mode 100644 internal/peer/chaincode/common.go delete mode 100644 internal/peer/chaincode/common_test.go delete mode 100644 internal/peer/chaincode/flags_test.go delete mode 100644 internal/peer/chaincode/install.go delete mode 100644 internal/peer/chaincode/install_test.go delete mode 100644 internal/peer/chaincode/instantiate.go delete mode 100644 internal/peer/chaincode/instantiate_test.go delete mode 100644 internal/peer/chaincode/invoke.go delete mode 100644 internal/peer/chaincode/invoke_test.go delete mode 100644 internal/peer/chaincode/list.go delete mode 100644 internal/peer/chaincode/list_test.go delete mode 100644 internal/peer/chaincode/mock/deliver.go delete mode 100644 internal/peer/chaincode/mock/deliver_client.go delete mode 100644 internal/peer/chaincode/mock/signer_serializer.go delete mode 100644 internal/peer/chaincode/package.go delete mode 100644 internal/peer/chaincode/package_test.go delete mode 100644 internal/peer/chaincode/query.go delete mode 100644 internal/peer/chaincode/query_test.go delete mode 100644 internal/peer/chaincode/signpackage.go delete mode 100644 internal/peer/chaincode/signpackage_test.go delete mode 100644 internal/peer/chaincode/testdata/connectionprofile-uneven.yaml delete mode 100644 internal/peer/chaincode/testdata/connectionprofile.yaml delete mode 100644 internal/peer/chaincode/testdata/src/chaincodes/noop/chaincode.go delete mode 100644 internal/peer/chaincode/upgrade.go delete mode 100644 internal/peer/chaincode/upgrade_test.go diff --git a/cmd/peer/main.go b/cmd/peer/main.go index e2cc3228287..7ad9010763f 100644 --- a/cmd/peer/main.go +++ b/cmd/peer/main.go @@ -12,7 +12,6 @@ import ( "strings" "github.com/hyperledger/fabric/bccsp/factory" - "github.com/hyperledger/fabric/internal/peer/chaincode" "github.com/hyperledger/fabric/internal/peer/channel" "github.com/hyperledger/fabric/internal/peer/common" "github.com/hyperledger/fabric/internal/peer/lifecycle" @@ -42,7 +41,6 @@ func main() { mainCmd.AddCommand(version.Cmd()) mainCmd.AddCommand(node.Cmd()) - mainCmd.AddCommand(chaincode.Cmd(nil, cryptoProvider)) mainCmd.AddCommand(channel.Cmd(nil)) mainCmd.AddCommand(lifecycle.Cmd(cryptoProvider)) mainCmd.AddCommand(snapshot.Cmd(cryptoProvider)) diff --git a/internal/peer/chaincode/chaincode.go b/internal/peer/chaincode/chaincode.go deleted file mode 100644 index c06491acb40..00000000000 --- a/internal/peer/chaincode/chaincode.go +++ /dev/null @@ -1,157 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "time" - - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/common/flogging" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/internal/peer/packaging" - "github.com/spf13/cobra" - "github.com/spf13/pflag" -) - -const ( - chainFuncName = "chaincode" - chainCmdDes = "Operate a chaincode: install|instantiate|invoke|package|query|signpackage|upgrade|list." -) - -var logger = flogging.MustGetLogger("chaincodeCmd") - -// XXX This is a terrible singleton hack, however -// it simply making a latent dependency explicit. -// It should be removed along with the other package -// scoped variables -var platformRegistry = packaging.NewRegistry(packaging.SupportedPlatforms...) - -func addFlags(cmd *cobra.Command) { - common.AddOrdererFlags(cmd) - flags := cmd.PersistentFlags() - flags.StringVarP(&transient, "transient", "", "", "Transient map of arguments in JSON encoding") -} - -// Cmd returns the cobra command for Chaincode -func Cmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - addFlags(chaincodeCmd) - - chaincodeCmd.AddCommand(installCmd(cf, nil, cryptoProvider)) - chaincodeCmd.AddCommand(instantiateCmd(cf, cryptoProvider)) - chaincodeCmd.AddCommand(invokeCmd(cf, cryptoProvider)) - chaincodeCmd.AddCommand(packageCmd(cf, nil, nil, cryptoProvider)) - chaincodeCmd.AddCommand(queryCmd(cf, cryptoProvider)) - chaincodeCmd.AddCommand(signpackageCmd(cf, cryptoProvider)) - chaincodeCmd.AddCommand(upgradeCmd(cf, cryptoProvider)) - chaincodeCmd.AddCommand(listCmd(cf, cryptoProvider)) - - return chaincodeCmd -} - -// Chaincode-related variables. -var ( - chaincodeLang string - chaincodeCtorJSON string - chaincodePath string - chaincodeName string - chaincodeUsr string // Not used - chaincodeQueryRaw bool - chaincodeQueryHex bool - channelID string - chaincodeVersion string - policy string - escc string - vscc string - policyMarshalled []byte - transient string - isInit bool - collectionsConfigFile string - collectionConfigBytes []byte - peerAddresses []string - tlsRootCertFiles []string - connectionProfile string - waitForEvent bool - waitForEventTimeout time.Duration -) - -var chaincodeCmd = &cobra.Command{ - Use: chainFuncName, - Short: fmt.Sprint(chainCmdDes), - Long: fmt.Sprint(chainCmdDes), - PersistentPreRun: func(cmd *cobra.Command, args []string) { - common.InitCmd(cmd, args) - common.SetOrdererEnv(cmd, args) - }, -} - -var flags *pflag.FlagSet - -func init() { - resetFlags() -} - -// Explicitly define a method to facilitate tests -func resetFlags() { - flags = &pflag.FlagSet{} - - flags.StringVarP(&chaincodeLang, "lang", "l", "golang", - fmt.Sprintf("Language the %s is written in", chainFuncName)) - flags.StringVarP(&chaincodeCtorJSON, "ctor", "c", "{}", - fmt.Sprintf("Constructor message for the %s in JSON format", chainFuncName)) - flags.StringVarP(&chaincodePath, "path", "p", common.UndefinedParamValue, - fmt.Sprintf("Path to %s", chainFuncName)) - flags.StringVarP(&chaincodeName, "name", "n", common.UndefinedParamValue, - "Name of the chaincode") - flags.StringVarP(&chaincodeVersion, "version", "v", common.UndefinedParamValue, - "Version of the chaincode specified in install/instantiate/upgrade commands") - flags.StringVarP(&chaincodeUsr, "username", "u", common.UndefinedParamValue, - "Username for chaincode operations when security is enabled") - flags.StringVarP(&channelID, "channelID", "C", "", - "The channel on which this command should be executed") - flags.StringVarP(&policy, "policy", "P", common.UndefinedParamValue, - "The endorsement policy associated to this chaincode") - flags.StringVarP(&escc, "escc", "E", common.UndefinedParamValue, - "The name of the endorsement system chaincode to be used for this chaincode") - flags.StringVarP(&vscc, "vscc", "V", common.UndefinedParamValue, - "The name of the verification system chaincode to be used for this chaincode") - flags.BoolVarP(&isInit, "isInit", "I", false, - "Is this invocation for init (useful for supporting legacy chaincodes in the new lifecycle)") - flags.BoolVarP(&getInstalledChaincodes, "installed", "", false, - "Get the installed chaincodes on a peer") - flags.BoolVarP(&getInstantiatedChaincodes, "instantiated", "", false, - "Get the instantiated chaincodes on a channel") - flags.StringVar(&collectionsConfigFile, "collections-config", common.UndefinedParamValue, - "The fully qualified path to the collection JSON file including the file name") - flags.StringArrayVarP(&peerAddresses, "peerAddresses", "", []string{common.UndefinedParamValue}, - "The addresses of the peers to connect to") - flags.StringArrayVarP(&tlsRootCertFiles, "tlsRootCertFiles", "", []string{common.UndefinedParamValue}, - "If TLS is enabled, the paths to the TLS root cert files of the peers to connect to. The order and number of certs specified should match the --peerAddresses flag") - flags.StringVarP(&connectionProfile, "connectionProfile", "", common.UndefinedParamValue, - "Connection profile that provides the necessary connection information for the network. Note: currently only supported for providing peer connection information") - flags.BoolVar(&waitForEvent, "waitForEvent", false, - "Whether to wait for the event from each peer's deliver filtered service signifying that the 'invoke' transaction has been committed successfully") - flags.DurationVar(&waitForEventTimeout, "waitForEventTimeout", 30*time.Second, - "Time to wait for the event from each peer's deliver filtered service signifying that the 'invoke' transaction has been committed successfully") - flags.BoolVarP(&createSignedCCDepSpec, "cc-package", "s", false, - "create CC deployment spec for owner endorsements instead of raw CC deployment spec") - flags.BoolVarP(&signCCDepSpec, "sign", "S", false, - "if creating CC deployment spec package for owner endorsements, also sign it with local MSP") - flags.StringVarP(&instantiationPolicy, "instantiate-policy", "i", "", - "instantiation policy for the chaincode") -} - -func attachFlags(cmd *cobra.Command, names []string) { - cmdFlags := cmd.Flags() - for _, name := range names { - if flag := flags.Lookup(name); flag != nil { - cmdFlags.AddFlag(flag) - } else { - logger.Fatalf("Could not find flag '%s' to attach to command '%s'", name, cmd.Name()) - } - } -} diff --git a/internal/peer/chaincode/common.go b/internal/peer/chaincode/common.go deleted file mode 100644 index 169f975c9e3..00000000000 --- a/internal/peer/chaincode/common.go +++ /dev/null @@ -1,890 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "crypto/tls" - "encoding/json" - "fmt" - "math" - "os" - "strings" - "sync" - - "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric-chaincode-go/shim" - pcommon "github.com/hyperledger/fabric-protos-go/common" - ab "github.com/hyperledger/fabric-protos-go/orderer" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/common/policydsl" - "github.com/hyperledger/fabric/common/util" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/internal/pkg/identity" - "github.com/hyperledger/fabric/protoutil" - "github.com/pkg/errors" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -// checkSpec to see if chaincode resides within current package capture for language. -func checkSpec(spec *pb.ChaincodeSpec) error { - // Don't allow nil value - if spec == nil { - return errors.New("expected chaincode specification, nil received") - } - if spec.ChaincodeId == nil { - return errors.New("expected chaincode ID, nil received") - } - - return platformRegistry.ValidateSpec(spec.Type.String(), spec.ChaincodeId.Path) -} - -// getChaincodeDeploymentSpec get chaincode deployment spec given the chaincode spec -func getChaincodeDeploymentSpec(spec *pb.ChaincodeSpec, crtPkg bool) (*pb.ChaincodeDeploymentSpec, error) { - var codePackageBytes []byte - if crtPkg { - var err error - if err = checkSpec(spec); err != nil { - return nil, err - } - - codePackageBytes, err = platformRegistry.GetDeploymentPayload(spec.Type.String(), spec.ChaincodeId.Path) - if err != nil { - return nil, errors.WithMessage(err, "error getting chaincode package bytes") - } - chaincodePath, err := platformRegistry.NormalizePath(spec.Type.String(), spec.ChaincodeId.Path) - if err != nil { - return nil, errors.WithMessage(err, "failed to normalize chaincode path") - } - spec.ChaincodeId.Path = chaincodePath - } - - return &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}, nil -} - -// getChaincodeSpec get chaincode spec from the cli cmd parameters -func getChaincodeSpec(cmd *cobra.Command) (*pb.ChaincodeSpec, error) { - spec := &pb.ChaincodeSpec{} - if err := checkChaincodeCmdParams(cmd); err != nil { - // unset usage silence because it's a command line usage error - cmd.SilenceUsage = false - return spec, err - } - - // Build the spec - input := chaincodeInput{} - if err := json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil { - return spec, errors.Wrap(err, "chaincode argument error") - } - input.IsInit = isInit - - chaincodeLang = strings.ToUpper(chaincodeLang) - spec = &pb.ChaincodeSpec{ - Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]), - ChaincodeId: &pb.ChaincodeID{Path: chaincodePath, Name: chaincodeName, Version: chaincodeVersion}, - Input: &input.ChaincodeInput, - } - return spec, nil -} - -// chaincodeInput is wrapper around the proto defined ChaincodeInput message that -// is decorated with a custom JSON unmarshaller. -type chaincodeInput struct { - pb.ChaincodeInput -} - -// UnmarshalJSON converts the string-based REST/JSON input to -// the []byte-based current ChaincodeInput structure. -func (c *chaincodeInput) UnmarshalJSON(b []byte) error { - sa := struct { - Function string - Args []string - }{} - err := json.Unmarshal(b, &sa) - if err != nil { - return err - } - allArgs := sa.Args - if sa.Function != "" { - allArgs = append([]string{sa.Function}, sa.Args...) - } - c.Args = util.ToChaincodeArgs(allArgs...) - return nil -} - -func chaincodeInvokeOrQuery(cmd *cobra.Command, invoke bool, cf *ChaincodeCmdFactory) (err error) { - spec, err := getChaincodeSpec(cmd) - if err != nil { - return err - } - - // call with empty txid to ensure production code generates a txid. - // otherwise, tests can explicitly set their own txid - txID := "" - - proposalResp, err := ChaincodeInvokeOrQuery( - spec, - channelID, - txID, - invoke, - cf.Signer, - cf.Certificate, - cf.EndorserClients, - cf.DeliverClients, - cf.BroadcastClient, - ) - if err != nil { - return errors.Errorf("%s - proposal response: %v", err, proposalResp) - } - - if invoke { - logger.Debugf("ESCC invoke result: %v", proposalResp) - pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(proposalResp.Payload) - if err != nil { - return errors.WithMessage(err, "error while unmarshalling proposal response payload") - } - ca, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension) - if err != nil { - return errors.WithMessage(err, "error while unmarshalling chaincode action") - } - if proposalResp.Endorsement == nil { - return errors.Errorf("endorsement failure during invoke. response: %v", proposalResp.Response) - } - logger.Infof("Chaincode invoke successful. result: %v", ca.Response) - } else { - if proposalResp == nil { - return errors.New("error during query: received nil proposal response") - } - if proposalResp.Endorsement == nil { - return errors.Errorf("endorsement failure during query. response: %v", proposalResp.Response) - } - - if chaincodeQueryRaw && chaincodeQueryHex { - return fmt.Errorf("options --raw (-r) and --hex (-x) are not compatible") - } - if chaincodeQueryRaw { - fmt.Println(proposalResp.Response.Payload) - return nil - } - if chaincodeQueryHex { - fmt.Printf("%x\n", proposalResp.Response.Payload) - return nil - } - fmt.Println(string(proposalResp.Response.Payload)) - } - return nil -} - -type endorsementPolicy struct { - ChannelConfigPolicy string `json:"channelConfigPolicy,omitempty"` - SignaturePolicy string `json:"signaturePolicy,omitempty"` -} - -type collectionConfigJson struct { - Name string `json:"name"` - Policy string `json:"policy"` - RequiredPeerCount *int32 `json:"requiredPeerCount"` - MaxPeerCount *int32 `json:"maxPeerCount"` - BlockToLive uint64 `json:"blockToLive"` - MemberOnlyRead bool `json:"memberOnlyRead"` - MemberOnlyWrite bool `json:"memberOnlyWrite"` - EndorsementPolicy *endorsementPolicy `json:"endorsementPolicy,omitempty"` -} - -// GetCollectionConfigFromFile retrieves the collection configuration -// from the supplied file; the supplied file must contain a -// json-formatted array of collectionConfigJson elements -func GetCollectionConfigFromFile(ccFile string) (*pb.CollectionConfigPackage, []byte, error) { - fileBytes, err := os.ReadFile(ccFile) - if err != nil { - return nil, nil, errors.Wrapf(err, "could not read file '%s'", ccFile) - } - - return getCollectionConfigFromBytes(fileBytes) -} - -// getCollectionConfig retrieves the collection configuration -// from the supplied byte array; the byte array must contain a -// json-formatted array of collectionConfigJson elements -func getCollectionConfigFromBytes(cconfBytes []byte) (*pb.CollectionConfigPackage, []byte, error) { - cconf := &[]collectionConfigJson{} - err := json.Unmarshal(cconfBytes, cconf) - if err != nil { - return nil, nil, errors.Wrap(err, "could not parse the collection configuration") - } - - ccarray := make([]*pb.CollectionConfig, 0, len(*cconf)) - for _, cconfitem := range *cconf { - p, err := policydsl.FromString(cconfitem.Policy) - if err != nil { - return nil, nil, errors.WithMessagef(err, "invalid policy %s", cconfitem.Policy) - } - - cpc := &pb.CollectionPolicyConfig{ - Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ - SignaturePolicy: p, - }, - } - - var ep *pb.ApplicationPolicy - if cconfitem.EndorsementPolicy != nil { - signaturePolicy := cconfitem.EndorsementPolicy.SignaturePolicy - channelConfigPolicy := cconfitem.EndorsementPolicy.ChannelConfigPolicy - ep, err = getApplicationPolicy(signaturePolicy, channelConfigPolicy) - if err != nil { - return nil, nil, errors.WithMessagef(err, "invalid endorsement policy [%#v]", cconfitem.EndorsementPolicy) - } - } - - // Set default requiredPeerCount and MaxPeerCount if not specified in json - requiredPeerCount := int32(0) - maxPeerCount := int32(1) - if cconfitem.RequiredPeerCount != nil { - requiredPeerCount = *cconfitem.RequiredPeerCount - } - if cconfitem.MaxPeerCount != nil { - maxPeerCount = *cconfitem.MaxPeerCount - } - - cc := &pb.CollectionConfig{ - Payload: &pb.CollectionConfig_StaticCollectionConfig{ - StaticCollectionConfig: &pb.StaticCollectionConfig{ - Name: cconfitem.Name, - MemberOrgsPolicy: cpc, - RequiredPeerCount: requiredPeerCount, - MaximumPeerCount: maxPeerCount, - BlockToLive: cconfitem.BlockToLive, - MemberOnlyRead: cconfitem.MemberOnlyRead, - MemberOnlyWrite: cconfitem.MemberOnlyWrite, - EndorsementPolicy: ep, - }, - }, - } - - ccarray = append(ccarray, cc) - } - - ccp := &pb.CollectionConfigPackage{Config: ccarray} - ccpBytes, err := proto.Marshal(ccp) - return ccp, ccpBytes, err -} - -func getApplicationPolicy(signaturePolicy, channelConfigPolicy string) (*pb.ApplicationPolicy, error) { - if signaturePolicy == "" && channelConfigPolicy == "" { - // no policy, no problem - return nil, nil - } - - if signaturePolicy != "" && channelConfigPolicy != "" { - // mo policies, mo problems - return nil, errors.New(`cannot specify both "--signature-policy" and "--channel-config-policy"`) - } - - var applicationPolicy *pb.ApplicationPolicy - if signaturePolicy != "" { - signaturePolicyEnvelope, err := policydsl.FromString(signaturePolicy) - if err != nil { - return nil, errors.Errorf("invalid signature policy: %s", signaturePolicy) - } - - applicationPolicy = &pb.ApplicationPolicy{ - Type: &pb.ApplicationPolicy_SignaturePolicy{ - SignaturePolicy: signaturePolicyEnvelope, - }, - } - } - - if channelConfigPolicy != "" { - applicationPolicy = &pb.ApplicationPolicy{ - Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ - ChannelConfigPolicyReference: channelConfigPolicy, - }, - } - } - - return applicationPolicy, nil -} - -func checkChaincodeCmdParams(cmd *cobra.Command) error { - // we need chaincode name for everything, including deploy - if chaincodeName == common.UndefinedParamValue { - return errors.Errorf("must supply value for %s name parameter", chainFuncName) - } - - if cmd.Name() == instantiateCmdName || cmd.Name() == installCmdName || - cmd.Name() == upgradeCmdName || cmd.Name() == packageCmdName { - if chaincodeVersion == common.UndefinedParamValue { - return errors.Errorf("chaincode version is not provided for %s", cmd.Name()) - } - - if escc != common.UndefinedParamValue { - logger.Infof("Using escc %s", escc) - } else { - logger.Info("Using default escc") - escc = "escc" - } - - if vscc != common.UndefinedParamValue { - logger.Infof("Using vscc %s", vscc) - } else { - logger.Info("Using default vscc") - vscc = "vscc" - } - - if policy != common.UndefinedParamValue { - p, err := policydsl.FromString(policy) - if err != nil { - return errors.Errorf("invalid policy %s", policy) - } - policyMarshalled = protoutil.MarshalOrPanic(p) - } - - if collectionsConfigFile != common.UndefinedParamValue { - var err error - _, collectionConfigBytes, err = GetCollectionConfigFromFile(collectionsConfigFile) - if err != nil { - return errors.WithMessagef(err, "invalid collection configuration in file %s", collectionsConfigFile) - } - } - } - - // Check that non-empty chaincode parameters contain only Args as a key. - // Type checking is done later when the JSON is actually unmarshaled - // into a pb.ChaincodeInput. To better understand what's going - // on here with JSON parsing see http://blog.golang.org/json-and-go - - // Generic JSON with interface{} - if chaincodeCtorJSON != "{}" { - var f interface{} - err := json.Unmarshal([]byte(chaincodeCtorJSON), &f) - if err != nil { - return errors.Wrap(err, "chaincode argument error") - } - m := f.(map[string]interface{}) - sm := make(map[string]interface{}) - for k := range m { - sm[strings.ToLower(k)] = m[k] - } - _, argsPresent := sm["args"] - _, funcPresent := sm["function"] - if !argsPresent || (len(m) == 2 && !funcPresent) || len(m) > 2 { - return errors.New("non-empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'") - } - } else { - if cmd == nil || (cmd != chaincodeInstallCmd && cmd != chaincodePackageCmd) { - return errors.New("empty JSON chaincode parameters must contain the following keys: 'Args' or 'Function' and 'Args'") - } - } - - return nil -} - -func validatePeerConnectionParameters(cmdName string) error { - if connectionProfile != common.UndefinedParamValue { - networkConfig, err := common.GetConfig(connectionProfile) - if err != nil { - return err - } - if len(networkConfig.Channels[channelID].Peers) != 0 { - peerAddresses = []string{} - tlsRootCertFiles = []string{} - for peer, peerChannelConfig := range networkConfig.Channels[channelID].Peers { - if peerChannelConfig.EndorsingPeer { - peerConfig, ok := networkConfig.Peers[peer] - if !ok { - return errors.Errorf("peer '%s' is defined in the channel config but doesn't have associated peer config", peer) - } - peerAddresses = append(peerAddresses, peerConfig.URL) - tlsRootCertFiles = append(tlsRootCertFiles, peerConfig.TLSCACerts.Path) - } - } - } - } - - // currently only support multiple peer addresses for invoke - multiplePeersAllowed := map[string]bool{ - "invoke": true, - } - _, ok := multiplePeersAllowed[cmdName] - if !ok && len(peerAddresses) > 1 { - return errors.Errorf("'%s' command can only be executed against one peer. received %d", cmdName, len(peerAddresses)) - } - - if len(tlsRootCertFiles) > len(peerAddresses) { - logger.Warningf("received more TLS root cert files (%d) than peer addresses (%d)", len(tlsRootCertFiles), len(peerAddresses)) - } - - if viper.GetBool("peer.tls.enabled") { - if len(tlsRootCertFiles) != len(peerAddresses) { - return errors.Errorf("number of peer addresses (%d) does not match the number of TLS root cert files (%d)", len(peerAddresses), len(tlsRootCertFiles)) - } - } else { - tlsRootCertFiles = nil - } - - return nil -} - -// ChaincodeCmdFactory holds the clients used by ChaincodeCmd -type ChaincodeCmdFactory struct { - EndorserClients []pb.EndorserClient - DeliverClients []pb.DeliverClient - Certificate tls.Certificate - Signer identity.SignerSerializer - BroadcastClient common.BroadcastClient -} - -// InitCmdFactory init the ChaincodeCmdFactory with default clients -func InitCmdFactory(cmdName string, isEndorserRequired, isOrdererRequired bool, cryptoProvider bccsp.BCCSP) (*ChaincodeCmdFactory, error) { - var err error - var endorserClients []pb.EndorserClient - var deliverClients []pb.DeliverClient - if isEndorserRequired { - if err = validatePeerConnectionParameters(cmdName); err != nil { - return nil, errors.WithMessage(err, "error validating peer connection parameters") - } - for i, address := range peerAddresses { - var tlsRootCertFile string - if tlsRootCertFiles != nil { - tlsRootCertFile = tlsRootCertFiles[i] - } - endorserClient, err := common.GetEndorserClientFnc(address, tlsRootCertFile) - if err != nil { - return nil, errors.WithMessagef(err, "error getting endorser client for %s", cmdName) - } - endorserClients = append(endorserClients, endorserClient) - deliverClient, err := common.GetPeerDeliverClientFnc(address, tlsRootCertFile) - if err != nil { - return nil, errors.WithMessagef(err, "error getting deliver client for %s", cmdName) - } - deliverClients = append(deliverClients, deliverClient) - } - if len(endorserClients) == 0 { - return nil, errors.New("no endorser clients retrieved - this might indicate a bug") - } - } - certificate, err := common.GetClientCertificateFnc() - if err != nil { - return nil, errors.WithMessage(err, "error getting client certificate") - } - - signer, err := common.GetDefaultSignerFnc() - if err != nil { - return nil, errors.WithMessage(err, "error getting default signer") - } - - var broadcastClient common.BroadcastClient - if isOrdererRequired { - if len(common.OrderingEndpoint) == 0 { - if len(endorserClients) == 0 { - return nil, errors.New("orderer is required, but no ordering endpoint or endorser client supplied") - } - endorserClient := endorserClients[0] - - orderingEndpoints, err := common.GetOrdererEndpointOfChainFnc(channelID, signer, endorserClient, cryptoProvider) - if err != nil { - return nil, errors.WithMessagef(err, "error getting channel (%s) orderer endpoint", channelID) - } - if len(orderingEndpoints) == 0 { - return nil, errors.Errorf("no orderer endpoints retrieved for channel %s, pass orderer endpoint with -o flag instead", channelID) - } - logger.Infof("Retrieved channel (%s) orderer endpoint: %s", channelID, orderingEndpoints[0]) - // override viper env - viper.Set("orderer.address", orderingEndpoints[0]) - } - - broadcastClient, err = common.GetBroadcastClientFnc() - if err != nil { - return nil, errors.WithMessage(err, "error getting broadcast client") - } - } - return &ChaincodeCmdFactory{ - EndorserClients: endorserClients, - DeliverClients: deliverClients, - Signer: signer, - BroadcastClient: broadcastClient, - Certificate: certificate, - }, nil -} - -// processProposals sends a signed proposal to a set of peers, and gathers all the responses. -func processProposals(endorserClients []pb.EndorserClient, signedProposal *pb.SignedProposal) ([]*pb.ProposalResponse, error) { - responsesCh := make(chan *pb.ProposalResponse, len(endorserClients)) - errorCh := make(chan error, len(endorserClients)) - wg := sync.WaitGroup{} - for _, endorser := range endorserClients { - wg.Add(1) - go func(endorser pb.EndorserClient) { - defer wg.Done() - proposalResp, err := endorser.ProcessProposal(context.Background(), signedProposal) - if err != nil { - errorCh <- err - return - } - responsesCh <- proposalResp - }(endorser) - } - wg.Wait() - close(responsesCh) - close(errorCh) - for err := range errorCh { - return nil, err - } - var responses []*pb.ProposalResponse - for response := range responsesCh { - responses = append(responses, response) - } - return responses, nil -} - -// ChaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the -// INVOKE form prints the ProposalResponse to STDOUT, and the QUERY form prints -// the query result on STDOUT. A command-line flag (-r, --raw) determines -// whether the query result is output as raw bytes, or as a printable string. -// The printable form is optionally (-x, --hex) a hexadecimal representation -// of the query response. If the query response is NIL, nothing is output. -// -// NOTE - Query will likely go away as all interactions with the endorser are -// Proposal and ProposalResponses -func ChaincodeInvokeOrQuery( - spec *pb.ChaincodeSpec, - cID string, - txID string, - invoke bool, - signer identity.SignerSerializer, - certificate tls.Certificate, - endorserClients []pb.EndorserClient, - deliverClients []pb.DeliverClient, - bc common.BroadcastClient, -) (*pb.ProposalResponse, error) { - // Build the ChaincodeInvocationSpec message - invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec} - - creator, err := signer.Serialize() - if err != nil { - return nil, errors.WithMessage(err, "error serializing identity") - } - - funcName := "invoke" - if !invoke { - funcName = "query" - } - - // extract the transient field if it exists - var tMap map[string][]byte - if transient != "" { - if err := json.Unmarshal([]byte(transient), &tMap); err != nil { - return nil, errors.Wrap(err, "error parsing transient string") - } - } - - prop, txid, err := protoutil.CreateChaincodeProposalWithTxIDAndTransient(pcommon.HeaderType_ENDORSER_TRANSACTION, cID, invocation, creator, txID, tMap) - if err != nil { - return nil, errors.WithMessagef(err, "error creating proposal for %s", funcName) - } - - signedProp, err := protoutil.GetSignedProposal(prop, signer) - if err != nil { - return nil, errors.WithMessagef(err, "error creating signed proposal for %s", funcName) - } - - responses, err := processProposals(endorserClients, signedProp) - if err != nil { - return nil, errors.WithMessagef(err, "error endorsing %s", funcName) - } - - if len(responses) == 0 { - // this should only happen if some new code has introduced a bug - return nil, errors.New("no proposal responses received - this might indicate a bug") - } - // all responses will be checked when the signed transaction is created. - // for now, just set this so we check the first response's status - proposalResp := responses[0] - - if invoke { - if proposalResp != nil { - if proposalResp.Response.Status >= shim.ERRORTHRESHOLD { - return proposalResp, nil - } - // assemble a signed transaction (it's an Envelope message) - env, err := protoutil.CreateSignedTx(prop, signer, responses...) - if err != nil { - return proposalResp, errors.WithMessage(err, "could not assemble transaction") - } - var dg *DeliverGroup - var ctx context.Context - if waitForEvent { - var cancelFunc context.CancelFunc - ctx, cancelFunc = context.WithTimeout(context.Background(), waitForEventTimeout) - defer cancelFunc() - - dg = NewDeliverGroup( - deliverClients, - peerAddresses, - signer, - certificate, - channelID, - txid, - ) - // connect to deliver service on all peers - err := dg.Connect(ctx) - if err != nil { - return nil, err - } - } - - // send the envelope for ordering - if err = bc.Send(env); err != nil { - return proposalResp, errors.WithMessagef(err, "error sending transaction for %s", funcName) - } - - if dg != nil && ctx != nil { - // wait for event that contains the txid from all peers - err = dg.Wait(ctx) - if err != nil { - return nil, err - } - } - } - } - - return proposalResp, nil -} - -// DeliverGroup holds all of the information needed to connect -// to a set of peers to wait for the interested txid to be -// committed to the ledgers of all peers. This functionality -// is currently implemented via the peer's DeliverFiltered service. -// An error from any of the peers/deliver clients will result in -// the invoke command returning an error. Only the first error that -// occurs will be set -type DeliverGroup struct { - Clients []*DeliverClient - Certificate tls.Certificate - ChannelID string - TxID string - Signer identity.SignerSerializer - mutex sync.Mutex - Error error - wg sync.WaitGroup -} - -// DeliverClient holds the client/connection related to a specific -// peer. The address is included for logging purposes -type DeliverClient struct { - Client pb.DeliverClient - Connection pb.Deliver_DeliverClient - Address string -} - -func NewDeliverGroup( - deliverClients []pb.DeliverClient, - peerAddresses []string, - signer identity.SignerSerializer, - certificate tls.Certificate, - channelID string, - txid string, -) *DeliverGroup { - clients := make([]*DeliverClient, len(deliverClients)) - for i, client := range deliverClients { - address := peerAddresses[i] - if address == "" { - address = viper.GetString("peer.address") - } - dc := &DeliverClient{ - Client: client, - Address: address, - } - clients[i] = dc - } - - dg := &DeliverGroup{ - Clients: clients, - Certificate: certificate, - ChannelID: channelID, - TxID: txid, - Signer: signer, - } - - return dg -} - -// Connect waits for all deliver clients in the group to connect to -// the peer's deliver service, receive an error, or for the context -// to timeout. An error will be returned whenever even a single -// deliver client fails to connect to its peer -func (dg *DeliverGroup) Connect(ctx context.Context) error { - dg.wg.Add(len(dg.Clients)) - for _, client := range dg.Clients { - go dg.ClientConnect(ctx, client) - } - readyCh := make(chan struct{}) - go dg.WaitForWG(readyCh) - - select { - case <-readyCh: - if dg.Error != nil { - err := errors.WithMessage(dg.Error, "failed to connect to deliver on all peers") - return err - } - case <-ctx.Done(): - err := errors.New("timed out waiting for connection to deliver on all peers") - return err - } - - return nil -} - -// ClientConnect sends a deliver seek info envelope using the -// provided deliver client, setting the deliverGroup's Error -// field upon any error -func (dg *DeliverGroup) ClientConnect(ctx context.Context, dc *DeliverClient) { - defer dg.wg.Done() - df, err := dc.Client.DeliverFiltered(ctx) - if err != nil { - err = errors.WithMessagef(err, "error connecting to deliver filtered at %s", dc.Address) - dg.setError(err) - return - } - defer df.CloseSend() - dc.Connection = df - - envelope := createDeliverEnvelope(dg.ChannelID, dg.Certificate, dg.Signer) - err = df.Send(envelope) - if err != nil { - err = errors.WithMessagef(err, "error sending deliver seek info envelope to %s", dc.Address) - dg.setError(err) - return - } -} - -// Wait waits for all deliver client connections in the group to -// either receive a block with the txid, an error, or for the -// context to timeout -func (dg *DeliverGroup) Wait(ctx context.Context) error { - if len(dg.Clients) == 0 { - return nil - } - - dg.wg.Add(len(dg.Clients)) - for _, client := range dg.Clients { - go dg.ClientWait(client) - } - readyCh := make(chan struct{}) - go dg.WaitForWG(readyCh) - - select { - case <-readyCh: - if dg.Error != nil { - return dg.Error - } - case <-ctx.Done(): - err := errors.New("timed out waiting for txid on all peers") - return err - } - - return nil -} - -// ClientWait waits for the specified deliver client to receive -// a block event with the requested txid -func (dg *DeliverGroup) ClientWait(dc *DeliverClient) { - defer dg.wg.Done() - for { - resp, err := dc.Connection.Recv() - if err != nil { - err = errors.WithMessagef(err, "error receiving from deliver filtered at %s", dc.Address) - dg.setError(err) - return - } - switch r := resp.Type.(type) { - case *pb.DeliverResponse_FilteredBlock: - filteredTransactions := r.FilteredBlock.FilteredTransactions - for _, tx := range filteredTransactions { - if tx.Txid == dg.TxID { - logger.Infof("txid [%s] committed with status (%s) at %s", dg.TxID, tx.TxValidationCode, dc.Address) - if tx.TxValidationCode != pb.TxValidationCode_VALID { - err = errors.Errorf("transaction invalidated with status (%s)", tx.TxValidationCode) - dg.setError(err) - } - return - } - } - case *pb.DeliverResponse_Status: - err = errors.Errorf("deliver completed with status (%s) before txid received", r.Status) - dg.setError(err) - return - default: - err = errors.Errorf("received unexpected response type (%T) from %s", r, dc.Address) - dg.setError(err) - return - } - } -} - -// WaitForWG waits for the deliverGroup's wait group and closes -// the channel when ready -func (dg *DeliverGroup) WaitForWG(readyCh chan struct{}) { - dg.wg.Wait() - close(readyCh) -} - -// setError serializes an error for the deliverGroup -func (dg *DeliverGroup) setError(err error) { - dg.mutex.Lock() - dg.Error = err - dg.mutex.Unlock() -} - -func createDeliverEnvelope( - channelID string, - certificate tls.Certificate, - signer identity.SignerSerializer, -) *pcommon.Envelope { - var tlsCertHash []byte - // check for client certificate and create hash if present - if len(certificate.Certificate) > 0 { - tlsCertHash = util.ComputeSHA256(certificate.Certificate[0]) - } - - start := &ab.SeekPosition{ - Type: &ab.SeekPosition_Newest{ - Newest: &ab.SeekNewest{}, - }, - } - - stop := &ab.SeekPosition{ - Type: &ab.SeekPosition_Specified{ - Specified: &ab.SeekSpecified{ - Number: math.MaxUint64, - }, - }, - } - - seekInfo := &ab.SeekInfo{ - Start: start, - Stop: stop, - Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, - } - - env, err := protoutil.CreateSignedEnvelopeWithTLSBinding( - pcommon.HeaderType_DELIVER_SEEK_INFO, - channelID, - signer, - seekInfo, - int32(0), - uint64(0), - tlsCertHash, - ) - if err != nil { - logger.Errorf("Error signing envelope: %s", err) - return nil - } - - return env -} diff --git a/internal/peer/chaincode/common_test.go b/internal/peer/chaincode/common_test.go deleted file mode 100644 index 885779a6337..00000000000 --- a/internal/peer/chaincode/common_test.go +++ /dev/null @@ -1,841 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC. All Rights Reserved. -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "sort" - "testing" - "time" - - "github.com/golang/protobuf/proto" - cb "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/common/policydsl" - "github.com/hyperledger/fabric/core/config/configtest" - "github.com/hyperledger/fabric/internal/peer/chaincode/mock" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/internal/pkg/identity" - . "github.com/onsi/gomega" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -//go:generate counterfeiter -o mock/signer_serializer.go --fake-name SignerSerializer . signerSerializer - -type signerSerializer interface { - identity.SignerSerializer -} - -//go:generate counterfeiter -o mock/deliver.go --fake-name Deliver . deliver - -type deliver interface { - pb.Deliver_DeliverClient -} - -//go:generate counterfeiter -o mock/deliver_client.go --fake-name PeerDeliverClient . peerDeliverClient - -type peerDeliverClient interface { - pb.DeliverClient -} - -func TestCheckChaincodeCmdParamsWithNewCallingSchema(t *testing.T) { - chaincodeCtorJSON = `{ "Args":["func", "param"] }` - chaincodePath = "some/path" - chaincodeName = "somename" - require := require.New(t) - result := checkChaincodeCmdParams(&cobra.Command{}) - - require.Nil(result) -} - -func TestCheckChaincodeCmdParamsWithOldCallingSchema(t *testing.T) { - chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }` - chaincodePath = "some/path" - chaincodeName = "somename" - require := require.New(t) - result := checkChaincodeCmdParams(&cobra.Command{}) - - require.Nil(result) -} - -func TestCheckChaincodeCmdParamsWithoutName(t *testing.T) { - chaincodeCtorJSON = `{ "Function":"func", "Args":["param"] }` - chaincodePath = "some/path" - chaincodeName = "" - require := require.New(t) - result := checkChaincodeCmdParams(&cobra.Command{}) - - require.Error(result) -} - -func TestCheckChaincodeCmdParamsWithFunctionOnly(t *testing.T) { - chaincodeCtorJSON = `{ "Function":"func" }` - chaincodePath = "some/path" - chaincodeName = "somename" - require := require.New(t) - result := checkChaincodeCmdParams(&cobra.Command{}) - - require.Error(result) -} - -func TestCheckChaincodeCmdParamsEmptyCtor(t *testing.T) { - chaincodeCtorJSON = `{}` - chaincodePath = "some/path" - chaincodeName = "somename" - require := require.New(t) - result := checkChaincodeCmdParams(&cobra.Command{}) - - require.Error(result) -} - -func TestCheckValidJSON(t *testing.T) { - validJSON := `{"Args":["a","b","c"]}` - input := &chaincodeInput{} - if err := json.Unmarshal([]byte(validJSON), &input); err != nil { - t.Fail() - t.Logf("Chaincode argument error: %s", err) - return - } - - validJSON = `{"Function":"f", "Args":["a","b","c"]}` - if err := json.Unmarshal([]byte(validJSON), &input); err != nil { - t.Fail() - t.Logf("Chaincode argument error: %s", err) - return - } - - validJSON = `{"Function":"f", "Args":[]}` - if err := json.Unmarshal([]byte(validJSON), &input); err != nil { - t.Fail() - t.Logf("Chaincode argument error: %s", err) - return - } - - validJSON = `{"Function":"f"}` - if err := json.Unmarshal([]byte(validJSON), &input); err != nil { - t.Fail() - t.Logf("Chaincode argument error: %s", err) - return - } -} - -func TestCheckInvalidJSON(t *testing.T) { - invalidJSON := `{["a","b","c"]}` - input := &chaincodeInput{} - if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil { - t.Fail() - t.Logf("Bar argument error should have been caught: %s", invalidJSON) - return - } - - invalidJSON = `{"Function":}` - if err := json.Unmarshal([]byte(invalidJSON), &input); err == nil { - t.Fail() - t.Logf("Chaincode argument error: %s", err) - t.Logf("Bar argument error should have been caught: %s", invalidJSON) - return - } -} - -const sampleCollectionConfigGood = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "requiredPeerCount": 3, - "maxPeerCount": 483279847, - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true - } -]` - -const sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true - } -]` - -const sampleCollectionConfigGoodWithSignaturePolicy = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "requiredPeerCount": 3, - "maxPeerCount": 483279847, - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy": "OR('A.member', 'B.member')" - } - } -]` - -const sampleCollectionConfigGoodWithChannelConfigPolicy = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "requiredPeerCount": 3, - "maxPeerCount": 483279847, - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "channelConfigPolicy": "/Channel/Application/Endorsement" - } - } -]` - -const sampleCollectionConfigBad = `[ - { - "name": "foo", - "policy": "barf", - "requiredPeerCount": 3, - "maxPeerCount": 483279847 - } -]` - -const sampleCollectionConfigBadInvalidSignaturePolicy = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "requiredPeerCount": 3, - "maxPeerCount": 483279847, - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy": "invalid" - } - } -]` - -const sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy = `[ - { - "name": "foo", - "policy": "OR('A.member', 'B.member')", - "requiredPeerCount": 3, - "maxPeerCount": 483279847, - "blockToLive":10, - "memberOnlyRead": true, - "memberOnlyWrite": true, - "endorsementPolicy": { - "signaturePolicy": "OR('A.member', 'B.member')", - "channelConfigPolicy": "/Channel/Application/Endorsement" - } - } -]` - -func TestCollectionParsing(t *testing.T) { - ccp, ccpBytes, err := getCollectionConfigFromBytes([]byte(sampleCollectionConfigGood)) - require.NoError(t, err) - require.NotNil(t, ccp) - require.NotNil(t, ccpBytes) - conf := ccp.Config[0].GetStaticCollectionConfig() - pol, _ := policydsl.FromString("OR('A.member', 'B.member')") - require.Equal(t, 3, int(conf.RequiredPeerCount)) - require.Equal(t, 483279847, int(conf.MaximumPeerCount)) - require.Equal(t, "foo", conf.Name) - require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) - require.Equal(t, 10, int(conf.BlockToLive)) - require.Equal(t, true, conf.MemberOnlyRead) - require.Nil(t, conf.EndorsementPolicy) - t.Logf("conf=%s", conf) - - // Test default values for RequiredPeerCount and MaxPeerCount - ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodNoMaxPeerCountOrRequiredPeerCount)) - require.NoError(t, err) - require.NotNil(t, ccp) - require.NotNil(t, ccpBytes) - conf = ccp.Config[0].GetStaticCollectionConfig() - pol, _ = policydsl.FromString("OR('A.member', 'B.member')") - require.Equal(t, 0, int(conf.RequiredPeerCount)) - require.Equal(t, 1, int(conf.MaximumPeerCount)) - require.Equal(t, "foo", conf.Name) - require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) - require.Equal(t, 10, int(conf.BlockToLive)) - require.Equal(t, true, conf.MemberOnlyRead) - require.Nil(t, conf.EndorsementPolicy) - t.Logf("conf=%s", conf) - - ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithSignaturePolicy)) - require.NoError(t, err) - require.NotNil(t, ccp) - require.NotNil(t, ccpBytes) - conf = ccp.Config[0].GetStaticCollectionConfig() - pol, _ = policydsl.FromString("OR('A.member', 'B.member')") - require.Equal(t, 3, int(conf.RequiredPeerCount)) - require.Equal(t, 483279847, int(conf.MaximumPeerCount)) - require.Equal(t, "foo", conf.Name) - require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) - require.Equal(t, 10, int(conf.BlockToLive)) - require.Equal(t, true, conf.MemberOnlyRead) - require.True(t, proto.Equal(pol, conf.EndorsementPolicy.GetSignaturePolicy())) - t.Logf("conf=%s", conf) - - ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(sampleCollectionConfigGoodWithChannelConfigPolicy)) - require.NoError(t, err) - require.NotNil(t, ccp) - require.NotNil(t, ccpBytes) - conf = ccp.Config[0].GetStaticCollectionConfig() - pol, _ = policydsl.FromString("OR('A.member', 'B.member')") - require.Equal(t, 3, int(conf.RequiredPeerCount)) - require.Equal(t, 483279847, int(conf.MaximumPeerCount)) - require.Equal(t, "foo", conf.Name) - require.True(t, proto.Equal(pol, conf.MemberOrgsPolicy.GetSignaturePolicy())) - require.Equal(t, 10, int(conf.BlockToLive)) - require.Equal(t, true, conf.MemberOnlyRead) - require.Equal(t, "/Channel/Application/Endorsement", conf.EndorsementPolicy.GetChannelConfigPolicyReference()) - t.Logf("conf=%s", conf) - - failureTests := []struct { - name string - collectionConfig string - expectedErr string - }{ - { - name: "Invalid member orgs policy", - collectionConfig: sampleCollectionConfigBad, - expectedErr: "invalid policy barf: unrecognized token 'barf' in policy string", - }, - { - name: "Invalid collection config", - collectionConfig: "barf", - expectedErr: "could not parse the collection configuration: invalid character 'b' looking for beginning of value", - }, - { - name: "Invalid signature policy", - collectionConfig: sampleCollectionConfigBadInvalidSignaturePolicy, - expectedErr: `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"", SignaturePolicy:"invalid"}]: invalid signature policy: invalid`, - }, - { - name: "Signature policy and channel config policy both specified", - collectionConfig: sampleCollectionConfigBadSignaturePolicyAndChannelConfigPolicy, - expectedErr: `invalid endorsement policy [&chaincode.endorsementPolicy{ChannelConfigPolicy:"/Channel/Application/Endorsement", SignaturePolicy:"OR('A.member', 'B.member')"}]: cannot specify both "--signature-policy" and "--channel-config-policy"`, - }, - } - - for _, test := range failureTests { - t.Run(test.name, func(t *testing.T) { - ccp, ccpBytes, err = getCollectionConfigFromBytes([]byte(test.collectionConfig)) - require.EqualError(t, err, test.expectedErr) - require.Nil(t, ccp) - require.Nil(t, ccpBytes) - }) - } -} - -func TestValidatePeerConnectionParams(t *testing.T) { - defer resetFlags() - defer viper.Reset() - require := require.New(t) - configtest.SetDevFabricConfigPath(t) - - // TLS disabled - viper.Set("peer.tls.enabled", false) - - // failure - more than one peer and TLS root cert - not invoke - resetFlags() - peerAddresses = []string{"peer0", "peer1"} - tlsRootCertFiles = []string{"cert0", "cert1"} - err := validatePeerConnectionParameters("query") - require.Error(err) - require.Contains(err.Error(), "command can only be executed against one peer") - - // success - peer provided and no TLS root certs - // TLS disabled - resetFlags() - peerAddresses = []string{"peer0"} - err = validatePeerConnectionParameters("query") - require.NoError(err) - require.Nil(tlsRootCertFiles) - - // success - more TLS root certs than peers - // TLS disabled - resetFlags() - peerAddresses = []string{"peer0"} - tlsRootCertFiles = []string{"cert0", "cert1"} - err = validatePeerConnectionParameters("invoke") - require.NoError(err) - require.Nil(tlsRootCertFiles) - - // success - multiple peers and no TLS root certs - invoke - // TLS disabled - resetFlags() - peerAddresses = []string{"peer0", "peer1"} - err = validatePeerConnectionParameters("invoke") - require.NoError(err) - require.Nil(tlsRootCertFiles) - - // TLS enabled - viper.Set("peer.tls.enabled", true) - - // failure - uneven number of peers and TLS root certs - invoke - // TLS enabled - resetFlags() - peerAddresses = []string{"peer0", "peer1"} - tlsRootCertFiles = []string{"cert0"} - err = validatePeerConnectionParameters("invoke") - require.Error(err) - require.Contains(err.Error(), fmt.Sprintf("number of peer addresses (%d) does not match the number of TLS root cert files (%d)", len(peerAddresses), len(tlsRootCertFiles))) - - // success - more than one peer and TLS root certs - invoke - // TLS enabled - resetFlags() - peerAddresses = []string{"peer0", "peer1"} - tlsRootCertFiles = []string{"cert0", "cert1"} - err = validatePeerConnectionParameters("invoke") - require.NoError(err) - - // failure - connection profile doesn't exist - resetFlags() - connectionProfile = "blah" - err = validatePeerConnectionParameters("invoke") - require.Error(err) - require.Contains(err.Error(), "error reading connection profile") - - // failure - connection profile has peer defined in channel config but - // not in peer config - resetFlags() - channelID = "mychannel" - connectionProfile = "testdata/connectionprofile-uneven.yaml" - err = validatePeerConnectionParameters("invoke") - require.Error(err) - require.Contains(err.Error(), "defined in the channel config but doesn't have associated peer config") - - // success - connection profile exists - resetFlags() - channelID = "mychannel" - connectionProfile = "testdata/connectionprofile.yaml" - err = validatePeerConnectionParameters("invoke") - require.NoError(err) -} - -func TestInitCmdFactoryFailures(t *testing.T) { - defer resetFlags() - require := require.New(t) - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.Nil(err) - - // failure validating peer connection parameters - resetFlags() - peerAddresses = []string{"peer0", "peer1"} - tlsRootCertFiles = []string{"cert0", "cert1"} - cf, err := InitCmdFactory("query", true, false, cryptoProvider) - require.Error(err) - require.Contains(err.Error(), "error validating peer connection parameters: 'query' command can only be executed against one peer") - require.Nil(cf) - - // failure - no peers supplied and endorser client is needed - resetFlags() - peerAddresses = []string{} - cf, err = InitCmdFactory("query", true, false, cryptoProvider) - require.Error(err) - require.Contains(err.Error(), "no endorser clients retrieved") - require.Nil(cf) - - // failure - orderer client is needed, ordering endpoint is empty and no - // endorser client supplied - resetFlags() - peerAddresses = nil - cf, err = InitCmdFactory("invoke", false, true, cryptoProvider) - require.Error(err) - require.Contains(err.Error(), "no ordering endpoint or endorser client supplied") - require.Nil(cf) -} - -func TestDeliverGroupConnect(t *testing.T) { - defer resetFlags() - g := NewGomegaWithT(t) - - // success - mockDeliverClients := []*DeliverClient{ - { - Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), - Address: "peer0", - }, - { - Client: getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0"), - Address: "peer1", - }, - } - dg := DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err := dg.Connect(context.Background()) - g.Expect(err).To(BeNil()) - - // failure - DeliverFiltered returns error - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredReturns(nil, errors.New("icecream")) - mockDeliverClients = []*DeliverClient{ - { - Client: mockDC, - Address: "peer0", - }, - } - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Connect(context.Background()) - g.Expect(err.Error()).To(ContainSubstring("error connecting to deliver filtered")) - g.Expect(err.Error()).To(ContainSubstring("icecream")) - - // failure - Send returns error - mockD := &mock.Deliver{} - mockD.SendReturns(errors.New("blah")) - mockDC.DeliverFilteredReturns(mockD, nil) - mockDeliverClients = []*DeliverClient{ - { - Client: mockDC, - Address: "peer0", - }, - } - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Connect(context.Background()) - g.Expect(err.Error()).To(ContainSubstring("error sending deliver seek info")) - g.Expect(err.Error()).To(ContainSubstring("blah")) - - // failure - deliver registration timeout - delayChan := make(chan struct{}) - mockDCDelay := getMockDeliverClientRegisterAfterDelay(delayChan) - mockDeliverClients = []*DeliverClient{ - { - Client: mockDCDelay, - Address: "peer0", - }, - } - ctx, cancelFunc := context.WithTimeout(context.Background(), 10*time.Millisecond) - defer cancelFunc() - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Connect(ctx) - g.Expect(err.Error()).To(ContainSubstring("timed out waiting for connection to deliver on all peers")) - close(delayChan) -} - -func TestDeliverGroupWait(t *testing.T) { - defer resetFlags() - g := NewGomegaWithT(t) - - // success - mockConn := &mock.Deliver{} - filteredResp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_FilteredBlock{FilteredBlock: createFilteredBlock(pb.TxValidationCode_VALID, "txid0")}, - } - mockConn.RecvReturns(filteredResp, nil) - mockDeliverClients := []*DeliverClient{ - { - Connection: mockConn, - Address: "peer0", - }, - } - dg := DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err := dg.Wait(context.Background()) - g.Expect(err).To(BeNil()) - - // failure - Recv returns error - mockConn = &mock.Deliver{} - mockConn.RecvReturns(nil, errors.New("avocado")) - mockDeliverClients = []*DeliverClient{ - { - Connection: mockConn, - Address: "peer0", - }, - } - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Wait(context.Background()) - g.Expect(err.Error()).To(ContainSubstring("error receiving from deliver filtered")) - g.Expect(err.Error()).To(ContainSubstring("avocado")) - - // failure - Recv returns unexpected type - mockConn = &mock.Deliver{} - resp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_Block{}, - } - mockConn.RecvReturns(resp, nil) - mockDeliverClients = []*DeliverClient{ - { - Connection: mockConn, - Address: "peer0", - }, - } - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Wait(context.Background()) - g.Expect(err.Error()).To(ContainSubstring("unexpected response type")) - - // failure - both connections return error - mockConn = &mock.Deliver{} - mockConn.RecvReturns(nil, errors.New("barbeque")) - mockConn2 := &mock.Deliver{} - mockConn2.RecvReturns(nil, errors.New("tofu")) - mockDeliverClients = []*DeliverClient{ - { - Connection: mockConn, - Address: "peerBBQ", - }, - { - Connection: mockConn2, - Address: "peerTOFU", - }, - } - dg = DeliverGroup{ - Clients: mockDeliverClients, - ChannelID: "testchannel", - Signer: &mock.SignerSerializer{}, - Certificate: tls.Certificate{ - Certificate: [][]byte{[]byte("test")}, - }, - TxID: "txid0", - } - err = dg.Wait(context.Background()) - g.Expect(err.Error()).To(SatisfyAny( - ContainSubstring("barbeque"), - ContainSubstring("tofu"))) -} - -func TestChaincodeInvokeOrQuery_waitForEvent(t *testing.T) { - defer resetFlags() - - waitForEvent = true - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err) - peerAddresses = []string{"peer0", "peer1"} - channelID := "testchannel" - txID := "txid0" - - t.Run("success - deliver clients returns event with expected txid", func(t *testing.T) { - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockCF.DeliverClients, - mockCF.BroadcastClient, - ) - require.NoError(t, err) - }) - - t.Run("success - one deliver client first receives block without txid and then one with txid", func(t *testing.T) { - filteredBlocks := []*pb.FilteredBlock{ - createFilteredBlock(pb.TxValidationCode_VALID, "theseare", "notthetxidsyouarelookingfor"), - createFilteredBlock(pb.TxValidationCode_VALID, "txid0"), - } - mockDCTwoBlocks := getMockDeliverClientRespondsWithFilteredBlocks(filteredBlocks) - mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") - mockDeliverClients := []pb.DeliverClient{mockDCTwoBlocks, mockDC} - - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockDeliverClients, - mockCF.BroadcastClient, - ) - require.NoError(t, err) - }) - - t.Run("failure - one of the deliver clients returns error", func(t *testing.T) { - mockDCErr := getMockDeliverClientWithErr("moist") - mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") - mockDeliverClients := []pb.DeliverClient{mockDCErr, mockDC} - - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockDeliverClients, - mockCF.BroadcastClient, - ) - require.Error(t, err) - require.Contains(t, err.Error(), "moist") - }) - - t.Run("failure - transaction committed with non-success validation code", func(t *testing.T) { - mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") - mockDCFail := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_ENDORSEMENT_POLICY_FAILURE, "txid0") - mockDeliverClients := []pb.DeliverClient{mockDCFail, mockDC} - - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockDeliverClients, - mockCF.BroadcastClient, - ) - require.Error(t, err) - require.Equal(t, err.Error(), "transaction invalidated with status (ENDORSEMENT_POLICY_FAILURE)") - }) - - t.Run("failure - deliver returns response status instead of block", func(t *testing.T) { - mockDC := &mock.PeerDeliverClient{} - mockDF := &mock.Deliver{} - resp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_Status{ - Status: cb.Status_FORBIDDEN, - }, - } - mockDF.RecvReturns(resp, nil) - mockDC.DeliverFilteredReturns(mockDF, nil) - mockDeliverClients := []pb.DeliverClient{mockDC} - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockDeliverClients, - mockCF.BroadcastClient, - ) - require.Error(t, err) - require.Equal(t, err.Error(), "deliver completed with status (FORBIDDEN) before txid received") - }) - - t.Run(" failure - timeout occurs - both deliver clients don't return an event with the expected txid before timeout", func(t *testing.T) { - delayChan := make(chan struct{}) - mockDCDelay := getMockDeliverClientRespondAfterDelay(delayChan, pb.TxValidationCode_VALID, "txid0") - mockDeliverClients := []pb.DeliverClient{mockDCDelay, mockDCDelay} - waitForEventTimeout = 10 * time.Millisecond - - _, err = ChaincodeInvokeOrQuery( - &pb.ChaincodeSpec{}, - channelID, - txID, - true, - mockCF.Signer, - mockCF.Certificate, - mockCF.EndorserClients, - mockDeliverClients, - mockCF.BroadcastClient, - ) - require.Error(t, err) - require.Contains(t, err.Error(), "timed out") - close(delayChan) - }) -} - -func TestProcessProposals(t *testing.T) { - // Build clients that return a range of status codes (for verifying each client is called). - mockClients := []pb.EndorserClient{} - for i := 2; i <= 5; i++ { - response := &pb.ProposalResponse{ - Response: &pb.Response{Status: int32(i * 100)}, - Endorsement: &pb.Endorsement{}, - } - mockClients = append(mockClients, common.GetMockEndorserClient(response, nil)) - } - mockErrorClient := common.GetMockEndorserClient(nil, errors.New("failed to call endorser")) - signedProposal := &pb.SignedProposal{} - t.Run("should process a proposal for a single peer", func(t *testing.T) { - responses, err := processProposals([]pb.EndorserClient{mockClients[0]}, signedProposal) - require.NoError(t, err) - require.Len(t, responses, 1) - require.Equal(t, responses[0].Response.Status, int32(200)) - }) - t.Run("should process a proposal for multiple peers", func(t *testing.T) { - responses, err := processProposals(mockClients, signedProposal) - require.NoError(t, err) - require.Len(t, responses, 4) - // Sort the statuses (as they may turn up in different order) before comparing. - statuses := []int32{} - for _, response := range responses { - statuses = append(statuses, response.Response.Status) - } - sort.Slice(statuses, func(i, j int) bool { return statuses[i] < statuses[j] }) - require.EqualValues(t, []int32{200, 300, 400, 500}, statuses) - }) - t.Run("should return an error from processing a proposal for a single peer", func(t *testing.T) { - responses, err := processProposals([]pb.EndorserClient{mockErrorClient}, signedProposal) - require.EqualError(t, err, "failed to call endorser") - require.Nil(t, responses) - }) - t.Run("should return an error from processing a proposal for a single peer within multiple peers", func(t *testing.T) { - responses, err := processProposals([]pb.EndorserClient{mockClients[0], mockErrorClient, mockClients[1]}, signedProposal) - require.EqualError(t, err, "failed to call endorser") - require.Nil(t, responses) - }) -} diff --git a/internal/peer/chaincode/flags_test.go b/internal/peer/chaincode/flags_test.go deleted file mode 100644 index 8d0d2b820cd..00000000000 --- a/internal/peer/chaincode/flags_test.go +++ /dev/null @@ -1,68 +0,0 @@ -/* -Copyright IBM Corp. 2016-2017 All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "testing" - - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -func TestOrdererFlags(t *testing.T) { - var ( - ca = "root.crt" - key = "client.key" - cert = "client.crt" - endpoint = "orderer.example.com:7050" - sn = "override.example.com" - ) - - testCmd := &cobra.Command{ - Use: "test", - Run: func(cmd *cobra.Command, args []string) { - t.Logf("rootcert: %s", viper.GetString("orderer.tls.rootcert.file")) - require.Equal(t, ca, viper.GetString("orderer.tls.rootcert.file")) - require.Equal(t, key, viper.GetString("orderer.tls.clientKey.file")) - require.Equal(t, cert, viper.GetString("orderer.tls.clientCert.file")) - require.Equal(t, endpoint, viper.GetString("orderer.address")) - require.Equal(t, sn, viper.GetString("orderer.tls.serverhostoverride")) - require.Equal(t, true, viper.GetBool("orderer.tls.enabled")) - require.Equal(t, true, viper.GetBool("orderer.tls.clientAuthRequired")) - }, - PersistentPreRun: func(cmd *cobra.Command, args []string) { - common.SetOrdererEnv(cmd, args) - }, - } - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - runCmd := Cmd(nil, cryptoProvider) - - runCmd.AddCommand(testCmd) - - runCmd.SetArgs([]string{ - "test", "--cafile", ca, "--keyfile", key, - "--certfile", cert, "--orderer", endpoint, "--tls", "--clientauth", - "--ordererTLSHostnameOverride", sn, - }) - err = runCmd.Execute() - require.NoError(t, err) - - // check env one more time - t.Logf("address: %s", viper.GetString("orderer.address")) - require.Equal(t, ca, viper.GetString("orderer.tls.rootcert.file")) - require.Equal(t, key, viper.GetString("orderer.tls.clientKey.file")) - require.Equal(t, cert, viper.GetString("orderer.tls.clientCert.file")) - require.Equal(t, endpoint, viper.GetString("orderer.address")) - require.Equal(t, sn, viper.GetString("orderer.tls.serverhostoverride")) - require.Equal(t, true, viper.GetBool("orderer.tls.enabled")) - require.Equal(t, true, viper.GetBool("orderer.tls.clientAuthRequired")) -} diff --git a/internal/peer/chaincode/install.go b/internal/peer/chaincode/install.go deleted file mode 100644 index 2d92a6d12cd..00000000000 --- a/internal/peer/chaincode/install.go +++ /dev/null @@ -1,278 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "os" - - "github.com/golang/protobuf/proto" - cb "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/core/common/ccpackage" - "github.com/hyperledger/fabric/core/common/ccprovider" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/internal/pkg/identity" - "github.com/hyperledger/fabric/protoutil" - "github.com/pkg/errors" - "github.com/spf13/cobra" -) - -var chaincodeInstallCmd *cobra.Command - -const ( - installCmdName = "install" -) - -// Installer holds the dependencies needed to install -// a chaincode -type Installer struct { - Command *cobra.Command - EndorserClients []pb.EndorserClient - Input *InstallInput - Signer identity.SignerSerializer - CryptoProvider bccsp.BCCSP -} - -// InstallInput holds the input parameters for installing -// a chaincode -type InstallInput struct { - Name string - Version string - Language string - PackageFile string - Path string -} - -// installCmd returns the cobra command for chaincode install -func installCmd(cf *ChaincodeCmdFactory, i *Installer, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeInstallCmd = &cobra.Command{ - Use: "install", - Short: "Install a chaincode.", - Long: "Install a chaincode on a peer. This installs a chaincode deployment spec package (if provided) or packages the specified chaincode before subsequently installing it.", - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - if i == nil { - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, false, cryptoProvider) - if err != nil { - return err - } - } - i = &Installer{ - Command: cmd, - EndorserClients: cf.EndorserClients, - Signer: cf.Signer, - CryptoProvider: cryptoProvider, - } - } - return i.installChaincode(args) - }, - } - flagList := []string{ - "lang", - "ctor", - "path", - "name", - "version", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - } - attachFlags(chaincodeInstallCmd, flagList) - - return chaincodeInstallCmd -} - -// installChaincode installs the chaincode -func (i *Installer) installChaincode(args []string) error { - if i.Command != nil { - // Parsing of the command line is done so silence cmd usage - i.Command.SilenceUsage = true - } - - i.setInput(args) - - // LSCC install - return i.install() -} - -func (i *Installer) setInput(args []string) { - i.Input = &InstallInput{ - Name: chaincodeName, - Version: chaincodeVersion, - Path: chaincodePath, - } - - if len(args) > 0 { - i.Input.PackageFile = args[0] - } -} - -// install installs a chaincode deployment spec to "peer.address" -// for use with lscc -func (i *Installer) install() error { - ccPkgMsg, err := i.getChaincodePackageMessage() - if err != nil { - return err - } - - proposal, err := i.createInstallProposal(ccPkgMsg) - if err != nil { - return err - } - - signedProposal, err := protoutil.GetSignedProposal(proposal, i.Signer) - if err != nil { - return errors.WithMessagef(err, "error creating signed proposal for %s", chainFuncName) - } - - return i.submitInstallProposal(signedProposal) -} - -func (i *Installer) submitInstallProposal(signedProposal *pb.SignedProposal) error { - // install is currently only supported for one peer - proposalResponse, err := i.EndorserClients[0].ProcessProposal(context.Background(), signedProposal) - if err != nil { - return errors.WithMessage(err, "error endorsing chaincode install") - } - - if proposalResponse == nil { - return errors.New("error during install: received nil proposal response") - } - - if proposalResponse.Response == nil { - return errors.New("error during install: received proposal response with nil response") - } - - if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { - return errors.Errorf("install failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) - } - logger.Infof("Installed remotely: %v", proposalResponse) - - return nil -} - -func (i *Installer) getChaincodePackageMessage() (proto.Message, error) { - // if no package provided, create one - if i.Input.PackageFile == "" { - if i.Input.Path == common.UndefinedParamValue || i.Input.Version == common.UndefinedParamValue || i.Input.Name == common.UndefinedParamValue { - return nil, errors.Errorf("must supply value for %s name, path and version parameters", chainFuncName) - } - // generate a raw ChaincodeDeploymentSpec - ccPkgMsg, err := genChaincodeDeploymentSpec(i.Command, i.Input.Name, i.Input.Version) - if err != nil { - return nil, err - } - return ccPkgMsg, nil - } - - // read in a package generated by the "package" sub-command (and perhaps signed - // by multiple owners with the "signpackage" sub-command) - // var cds *pb.ChaincodeDeploymentSpec - ccPkgMsg, cds, err := getPackageFromFile(i.Input.PackageFile, i.CryptoProvider) - if err != nil { - return nil, err - } - - // get the chaincode details from cds - cName := cds.ChaincodeSpec.ChaincodeId.Name - cVersion := cds.ChaincodeSpec.ChaincodeId.Version - - // if user provided chaincodeName, use it for validation - if i.Input.Name != "" && i.Input.Name != cName { - return nil, errors.Errorf("chaincode name %s does not match name %s in package", i.Input.Name, cName) - } - - // if user provided chaincodeVersion, use it for validation - if i.Input.Version != "" && i.Input.Version != cVersion { - return nil, errors.Errorf("chaincode version %s does not match version %s in packages", i.Input.Version, cVersion) - } - - return ccPkgMsg, nil -} - -func (i *Installer) createInstallProposal(msg proto.Message) (*pb.Proposal, error) { - creator, err := i.Signer.Serialize() - if err != nil { - return nil, errors.WithMessage(err, "error serializing identity") - } - - prop, _, err := protoutil.CreateInstallProposalFromCDS(msg, creator) - if err != nil { - return nil, errors.WithMessagef(err, "error creating proposal for %s", chainFuncName) - } - - return prop, nil -} - -// genChaincodeDeploymentSpec creates ChaincodeDeploymentSpec as the package to install -func genChaincodeDeploymentSpec(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) { - if existed, _ := ccprovider.ChaincodePackageExists(chaincodeName, chaincodeVersion); existed { - return nil, errors.Errorf("chaincode %s:%s already exists", chaincodeName, chaincodeVersion) - } - - spec, err := getChaincodeSpec(cmd) - if err != nil { - return nil, err - } - - cds, err := getChaincodeDeploymentSpec(spec, true) - if err != nil { - return nil, errors.WithMessagef(err, "error getting chaincode deployment spec for %s", chaincodeName) - } - - return cds, nil -} - -// getPackageFromFile get the chaincode package from file and the extracted ChaincodeDeploymentSpec -func getPackageFromFile(ccPkgFile string, cryptoProvider bccsp.BCCSP) (proto.Message, *pb.ChaincodeDeploymentSpec, error) { - ccPkgBytes, err := os.ReadFile(ccPkgFile) - if err != nil { - return nil, nil, err - } - - // the bytes should be a valid package (CDS or SignedCDS) - ccpack, err := ccprovider.GetCCPackage(ccPkgBytes, cryptoProvider) - if err != nil { - return nil, nil, err - } - - // either CDS or Envelope - o := ccpack.GetPackageObject() - - // try CDS first - cds, ok := o.(*pb.ChaincodeDeploymentSpec) - if !ok || cds == nil { - // try Envelope next - env, ok := o.(*cb.Envelope) - if !ok || env == nil { - return nil, nil, errors.New("error extracting valid chaincode package") - } - - // this will check for a valid package Envelope - _, sCDS, err := ccpackage.ExtractSignedCCDepSpec(env) - if err != nil { - return nil, nil, errors.WithMessage(err, "error extracting valid signed chaincode package") - } - - // ...and get the CDS at last - cds, err = protoutil.UnmarshalChaincodeDeploymentSpec(sCDS.ChaincodeDeploymentSpec) - if err != nil { - return nil, nil, errors.WithMessage(err, "error extracting chaincode deployment spec") - } - - err = platformRegistry.ValidateDeploymentSpec(cds.ChaincodeSpec.Type.String(), cds.CodePackage) - if err != nil { - return nil, nil, errors.WithMessage(err, "chaincode deployment spec validation failed") - } - } - - return o, cds, nil -} diff --git a/internal/peer/chaincode/install_test.go b/internal/peer/chaincode/install_test.go deleted file mode 100644 index 68781669af6..00000000000 --- a/internal/peer/chaincode/install_test.go +++ /dev/null @@ -1,152 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "os" - "testing" - - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -func initInstallTest(t *testing.T, fsPath string, ec pb.EndorserClient, mockResponse *pb.ProposalResponse) (*cobra.Command, *ChaincodeCmdFactory) { - viper.Set("peer.fileSystemPath", fsPath) - - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %v", err) - } - - if mockResponse == nil { - mockResponse = &pb.ProposalResponse{ - Response: &pb.Response{Status: 200}, - Endorsement: &pb.Endorsement{}, - } - } - if ec == nil { - ec = common.GetMockEndorserClient(mockResponse, nil) - } - - mockCF := &ChaincodeCmdFactory{ - Signer: signer, - EndorserClients: []pb.EndorserClient{ec}, - } - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - cmd := installCmd(mockCF, nil, cryptoProvider) - addFlags(cmd) - - return cmd, mockCF -} - -func TestInstallBadVersion(t *testing.T) { - fsPath := t.TempDir() - - cmd, _ := initInstallTest(t, fsPath, nil, nil) - - args := []string{"-n", "mychaincode", "-p", "github.com/hyperledger/fabric/internal/peer/chaincode/testdata/src/chaincodes/noop"} - cmd.SetArgs(args) - - if err := cmd.Execute(); err == nil { - t.Fatal("Expected error executing install command for version not specified") - } -} - -func TestInstallNonExistentCC(t *testing.T) { - fsPath := t.TempDir() - - cmd, _ := initInstallTest(t, fsPath, nil, nil) - - args := []string{"-n", "badmychaincode", "-p", "github.com/hyperledger/fabric/internal/peer/chaincode/testdata/src/chaincodes/bad_mychaincode", "-v", "testversion"} - cmd.SetArgs(args) - - if err := cmd.Execute(); err == nil { - t.Fatal("Expected error executing install command for bad chaincode") - } - - if _, err := os.Stat(fsPath + "/chaincodes/badmychaincode.testversion"); err == nil { - t.Fatal("chaincode mychaincode.testversion should not exist") - } -} - -func TestInstallFromPackage(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", ccpackfile}, false) - if err != nil { - t.Fatalf("could not create package :%v", err) - } - - fsPath := t.TempDir() - - cmd, mockCF := initInstallTest(t, fsPath, nil, nil) - - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 200}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClient := common.GetMockEndorserClient(mockResponse, nil) - mockCF.EndorserClients = []pb.EndorserClient{mockEndorserClient} - - args := []string{ccpackfile} - cmd.SetArgs(args) - - if err := cmd.Execute(); err != nil { - t.Fatal("error executing install command from package") - } -} - -func TestInstallFromBadPackage(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := os.WriteFile(ccpackfile, []byte("really bad CC package"), 0o700) - if err != nil { - t.Fatalf("could not create package :%v", err) - } - - fsPath := t.TempDir() - - cmd, _ := initInstallTest(t, fsPath, nil, nil) - - args := []string{ccpackfile} - cmd.SetArgs(args) - - if err := cmd.Execute(); err == nil { - t.Fatal("expected error installing bad package") - } -} - -func installCC(t *testing.T) error { - defer viper.Reset() - - fsPath := t.TempDir() - cmd, _ := initInstallTest(t, fsPath, nil, nil) - - args := []string{"-n", "mychaincode", "-p", "github.com/hyperledger/fabric/internal/peer/chaincode/testdata/src/chaincodes/noop", "-v", "anotherversion"} - cmd.SetArgs(args) - - if err := cmd.Execute(); err != nil { - return fmt.Errorf("Run chaincode upgrade cmd error:%v", err) - } - - return nil -} - -func TestInstall(t *testing.T) { - if err := installCC(t); err != nil { - t.Fatalf("Install failed with error: %v", err) - } -} diff --git a/internal/peer/chaincode/instantiate.go b/internal/peer/chaincode/instantiate.go deleted file mode 100644 index fe73afaca38..00000000000 --- a/internal/peer/chaincode/instantiate.go +++ /dev/null @@ -1,132 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "errors" - "fmt" - - protcommon "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/protoutil" - "github.com/spf13/cobra" -) - -var chaincodeInstantiateCmd *cobra.Command - -const instantiateCmdName = "instantiate" - -const instantiateDesc = "Deploy the specified chaincode to the network." - -// instantiateCmd returns the cobra command for Chaincode Deploy -func instantiateCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeInstantiateCmd = &cobra.Command{ - Use: instantiateCmdName, - Short: fmt.Sprint(instantiateDesc), - Long: fmt.Sprint(instantiateDesc), - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - return chaincodeDeploy(cmd, args, cf, cryptoProvider) - }, - } - flagList := []string{ - "lang", - "ctor", - "name", - "channelID", - "version", - "policy", - "escc", - "vscc", - "collections-config", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - } - attachFlags(chaincodeInstantiateCmd, flagList) - - return chaincodeInstantiateCmd -} - -// instantiate the command via Endorser -func instantiate(cmd *cobra.Command, cf *ChaincodeCmdFactory) (*protcommon.Envelope, error) { - spec, err := getChaincodeSpec(cmd) - if err != nil { - return nil, err - } - - cds, err := getChaincodeDeploymentSpec(spec, false) - if err != nil { - return nil, fmt.Errorf("error getting chaincode code %s: %s", chaincodeName, err) - } - - creator, err := cf.Signer.Serialize() - if err != nil { - return nil, fmt.Errorf("error serializing identity: %s", err) - } - - prop, _, err := protoutil.CreateDeployProposalFromCDS(channelID, cds, creator, policyMarshalled, []byte(escc), []byte(vscc), collectionConfigBytes) - if err != nil { - return nil, fmt.Errorf("error creating proposal %s: %s", chainFuncName, err) - } - - var signedProp *pb.SignedProposal - signedProp, err = protoutil.GetSignedProposal(prop, cf.Signer) - if err != nil { - return nil, fmt.Errorf("error creating signed proposal %s: %s", chainFuncName, err) - } - - // instantiate is currently only supported for one peer - proposalResponse, err := cf.EndorserClients[0].ProcessProposal(context.Background(), signedProp) - if err != nil { - return nil, fmt.Errorf("error endorsing %s: %s", chainFuncName, err) - } - - if proposalResponse != nil { - // assemble a signed transaction (it's an Envelope message) - env, err := protoutil.CreateSignedTx(prop, cf.Signer, proposalResponse) - if err != nil { - return nil, fmt.Errorf("could not assemble transaction, err %s", err) - } - - return env, nil - } - - return nil, nil -} - -// chaincodeDeploy instantiates the chaincode. On success, the chaincode name -// (hash) is printed to STDOUT for use by subsequent chaincode-related CLI -// commands. -func chaincodeDeploy(cmd *cobra.Command, args []string, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - if channelID == "" { - return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") - } - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, true, cryptoProvider) - if err != nil { - return err - } - } - defer cf.BroadcastClient.Close() - env, err := instantiate(cmd, cf) - if err != nil { - return err - } - - if env != nil { - err = cf.BroadcastClient.Send(env) - } - - return err -} diff --git a/internal/peer/chaincode/instantiate_test.go b/internal/peer/chaincode/instantiate_test.go deleted file mode 100644 index 816e4977290..00000000000 --- a/internal/peer/chaincode/instantiate_test.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "testing" - - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/stretchr/testify/require" -) - -func TestInstantiateCmd(t *testing.T) { - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err, "Error getting mock chaincode command factory") - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - // basic function tests - tests := []struct { - name string - args []string - errorExpected bool - errMsg string - }{ - { - name: "successful", - args: []string{"-n", "example02", "-v", "anotherversion", "-C", "mychannel", "-c", "{\"Args\": [\"init\",\"a\",\"100\",\"b\",\"200\"]}"}, - errorExpected: false, - errMsg: "Run chaincode instantiate cmd error", - }, - { - name: "no option", - args: []string{}, - errorExpected: true, - errMsg: "Expected error executing instantiate command without required options", - }, - { - name: "missing version", - args: []string{"-n", "example02", "-C", "mychannel", "-c", "{\"Args\": [\"init\",\"a\",\"100\",\"b\",\"200\"]}"}, - errorExpected: true, - errMsg: "Expected error executing instantiate command without the -v option", - }, - { - name: "missing name", - args: []string{"-v", "anotherversion", "-C", "mychannel", "-c", "{\"Args\": [\"init\",\"a\",\"100\",\"b\",\"200\"]}"}, - errorExpected: true, - errMsg: "Expected error executing instantiate command without the -n option", - }, - { - name: "missing channelID", - args: []string{"-n", "example02", "-v", "anotherversion", "-c", "{\"Args\": [\"init\",\"a\",\"100\",\"b\",\"200\"]}"}, - errorExpected: true, - errMsg: "Expected error executing instantiate command without the -C option", - }, - { - name: "missing ctor", - args: []string{"-n", "example02", "-C", "mychannel", "-v", "anotherversion"}, - errorExpected: true, - errMsg: "Expected error executing instantiate command without the -c option", - }, - { - name: "successful with policy", - args: []string{"-P", "OR('MSP.member', 'MSP.WITH.DOTS.member', 'MSP-WITH-DASHES.member')", "-n", "example02", "-v", "anotherversion", "-C", "mychannel", "-c", "{\"Args\": [\"init\",\"a\",\"100\",\"b\",\"200\"]}"}, - errorExpected: false, - errMsg: "Run chaincode instantiate cmd error", - }, - } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - resetFlags() - cmd := instantiateCmd(mockCF, cryptoProvider) - addFlags(cmd) - cmd.SetArgs(test.args) - err = cmd.Execute() - checkError(t, err, test.errorExpected, test.errMsg) - }) - } -} - -func checkError(t *testing.T, err error, expectedError bool, msg string) { - if expectedError { - require.Error(t, err, msg) - } else { - require.NoError(t, err, msg) - } -} diff --git a/internal/peer/chaincode/invoke.go b/internal/peer/chaincode/invoke.go deleted file mode 100644 index a428d0eae74..00000000000 --- a/internal/peer/chaincode/invoke.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - - "github.com/hyperledger/fabric/bccsp" - "github.com/pkg/errors" - "github.com/spf13/cobra" -) - -var chaincodeInvokeCmd *cobra.Command - -// invokeCmd returns the cobra command for Chaincode Invoke -func invokeCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeInvokeCmd = &cobra.Command{ - Use: "invoke", - Short: fmt.Sprintf("Invoke the specified %s.", chainFuncName), - Long: fmt.Sprintf("Invoke the specified %s. It will try to commit the endorsed transaction to the network.", chainFuncName), - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - return chaincodeInvoke(cmd, cf, cryptoProvider) - }, - } - flagList := []string{ - "name", - "ctor", - "isInit", - "channelID", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - "waitForEvent", - "waitForEventTimeout", - } - attachFlags(chaincodeInvokeCmd, flagList) - - return chaincodeInvokeCmd -} - -func chaincodeInvoke(cmd *cobra.Command, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - if channelID == "" { - return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") - } - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, true, cryptoProvider) - if err != nil { - return err - } - } - defer cf.BroadcastClient.Close() - - return chaincodeInvokeOrQuery(cmd, true, cf) -} diff --git a/internal/peer/chaincode/invoke_test.go b/internal/peer/chaincode/invoke_test.go deleted file mode 100644 index 6bcc5560819..00000000000 --- a/internal/peer/chaincode/invoke_test.go +++ /dev/null @@ -1,411 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "errors" - "fmt" - "testing" - "time" - - cb "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/common/flogging/floggingtest" - "github.com/hyperledger/fabric/internal/peer/chaincode/mock" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/msp" - "github.com/hyperledger/fabric/protoutil" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" -) - -func TestInvokeCmd(t *testing.T) { - defer viper.Reset() - defer resetFlags() - - resetFlags() - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err, "Error getting mock chaincode command factory") - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - // Error case 0: no channelID specified - cmd := invokeCmd(mockCF, cryptoProvider) - addFlags(cmd) - args := []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "'peer chaincode invoke' command should have returned error when called without -C flag") - - // Success case - cmd = invokeCmd(mockCF, cryptoProvider) - addFlags(cmd) - args = []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} - cmd.SetArgs(args) - err = cmd.Execute() - require.NoError(t, err, "Run chaincode invoke cmd error") - - // set timeout for error cases - viper.Set("peer.client.connTimeout", 10*time.Millisecond) - - // Error case 1: no orderer endpoints - t.Logf("Start error case 1: no orderer endpoints") - getEndorserClient := common.GetEndorserClientFnc - getOrdererEndpointOfChain := common.GetOrdererEndpointOfChainFnc - getBroadcastClient := common.GetBroadcastClientFnc - getDefaultSigner := common.GetDefaultSignerFnc - getDeliverClient := common.GetDeliverClientFnc - getPeerDeliverClient := common.GetPeerDeliverClientFnc - defer func() { - common.GetEndorserClientFnc = getEndorserClient - common.GetOrdererEndpointOfChainFnc = getOrdererEndpointOfChain - common.GetBroadcastClientFnc = getBroadcastClient - common.GetDefaultSignerFnc = getDefaultSigner - common.GetDeliverClientFnc = getDeliverClient - common.GetPeerDeliverClientFnc = getPeerDeliverClient - }() - common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { - return mockCF.EndorserClients[0], nil - } - common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { - return []string{}, nil - } - cmd = invokeCmd(nil, cryptoProvider) - addFlags(cmd) - args = []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err) - - // Error case 2: getEndorserClient returns error - t.Logf("Start error case 2: getEndorserClient returns error") - common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - - // Error case 3: getDeliverClient returns error - t.Logf("Start error case 3: getDeliverClient returns error") - common.GetDeliverClientFnc = func(string, string) (pb.Deliver_DeliverClient, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - - // Error case 4 : getPeerDeliverClient returns error - t.Logf("Start error case 4: getPeerDeliverClient returns error") - common.GetPeerDeliverClientFnc = func(string, string) (pb.DeliverClient, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - - // Error case 5: getDefaultSignerFnc returns error - t.Logf("Start error case 5: getDefaultSignerFnc returns error") - common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { - return mockCF.EndorserClients[0], nil - } - common.GetPeerDeliverClientFnc = func(string, string) (pb.DeliverClient, error) { - return mockCF.DeliverClients[0], nil - } - common.GetDefaultSignerFnc = func() (msp.SigningIdentity, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - common.GetDefaultSignerFnc = common.GetDefaultSigner - - // Error case 6: getOrdererEndpointOfChainFnc returns error - t.Logf("Start error case 6: getOrdererEndpointOfChainFnc returns error") - common.GetEndorserClientFnc = func(string, string) (pb.EndorserClient, error) { - return mockCF.EndorserClients[0], nil - } - common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - - // Error case 7: getBroadcastClient returns error - t.Logf("Start error case 7: getBroadcastClient returns error") - common.GetOrdererEndpointOfChainFnc = func(chainID string, signer common.Signer, endorserClient pb.EndorserClient, cryptoProvider bccsp.BCCSP) ([]string, error) { - return []string{"localhost:9999"}, nil - } - common.GetBroadcastClientFnc = func() (common.BroadcastClient, error) { - return nil, errors.New("error") - } - err = cmd.Execute() - require.Error(t, err) - - // Success case - t.Logf("Start success case") - common.GetBroadcastClientFnc = func() (common.BroadcastClient, error) { - return mockCF.BroadcastClient, nil - } - err = cmd.Execute() - require.NoError(t, err) -} - -func TestInvokeCmdSimulateESCCPluginResponse(t *testing.T) { - defer resetFlags() - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err, "Error getting mock chaincode command factory") - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - // success case - simulate an ESCC plugin that endorses a chaincode response - // with status greater than shim.ERRORTHRESHOLD or even shim.ERROR - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 504}, - Endorsement: &pb.Endorsement{}, - } - mockCF.EndorserClients = []pb.EndorserClient{ - common.GetMockEndorserClient(mockResponse, nil), - common.GetMockEndorserClient(mockResponse, nil), - } - - // set logger to logger with a backend that writes to a byte buffer - oldLogger := logger - defer func() { logger = oldLogger }() - l, recorder := floggingtest.NewTestLogger(t) - logger = l - - cmd := invokeCmd(mockCF, cryptoProvider) - addFlags(cmd) - args := []string{"-n", "example02", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}", "-C", "mychannel"} - cmd.SetArgs(args) - - err = cmd.Execute() - require.NoError(t, err, "Run chaincode invoke cmd error") - - require.NotEmpty(t, recorder.MessagesContaining("Chaincode invoke successful"), "missing invoke success log record") - require.NotEmpty(t, recorder.MessagesContaining("result: "), "missing result log record") -} - -func TestInvokeCmdEndorsementError(t *testing.T) { - defer resetFlags() - mockCF, err := getMockChaincodeCmdFactoryWithErr() - require.NoError(t, err, "Error getting mock chaincode command factory") - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - cmd := invokeCmd(mockCF, cryptoProvider) - addFlags(cmd) - args := []string{"-n", "example02", "-C", "mychannel", "-c", "{\"Args\": [\"invoke\",\"a\",\"b\",\"10\"]}"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "Expected error executing invoke command") -} - -func TestInvokeCmdEndorsementFailure(t *testing.T) { - defer resetFlags() - ccRespStatus := [2]int32{502, 400} - ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")} - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - for i := 0; i < 2; i++ { - mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i]) - require.NoError(t, err, "Error getting mock chaincode command factory") - - cmd := invokeCmd(mockCF, cryptoProvider) - addFlags(cmd) - args := []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"invokeinvalid\",\"a\",\"b\",\"10\"]}"} - cmd.SetArgs(args) - - err = cmd.Execute() - require.Error(t, err) - require.Contains(t, err.Error(), "endorsement failure during invoke") - require.Contains(t, err.Error(), fmt.Sprintf("response: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i])) - } -} - -// Returns mock chaincode command factory with multiple endorser and deliver clients -func getMockChaincodeCmdFactory() (*ChaincodeCmdFactory, error) { - signer, err := common.GetDefaultSigner() - if err != nil { - return nil, err - } - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 200}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil), common.GetMockEndorserClient(mockResponse, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockDC := getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_VALID, "txid0") - mockDeliverClients := []pb.DeliverClient{mockDC, mockDC} - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - DeliverClients: mockDeliverClients, - } - return mockCF, nil -} - -// Returns mock chaincode command factory that is constructed with an endorser -// client that returns an error for proposal request and a deliver client -func getMockChaincodeCmdFactoryWithErr() (*ChaincodeCmdFactory, error) { - signer, err := common.GetDefaultSigner() - if err != nil { - return nil, err - } - - errMsg := "invoke error" - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(nil, errors.New(errMsg))} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockDeliverClients := []pb.DeliverClient{getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode_INVALID_OTHER_REASON, "txid0")} - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - DeliverClients: mockDeliverClients, - } - return mockCF, nil -} - -// Returns mock chaincode command factory with an endorser client (that fails) and -// a deliver client -func getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus int32, ccRespPayload []byte) (*ChaincodeCmdFactory, error) { - signer, err := common.GetDefaultSigner() - if err != nil { - return nil, err - } - - // create a proposal from a ChaincodeInvocationSpec - prop, _, err := protoutil.CreateChaincodeProposal(cb.HeaderType_ENDORSER_TRANSACTION, "testchannelid", createCIS(), nil) - if err != nil { - return nil, fmt.Errorf("Could not create chaincode proposal, err %s\n", err) - } - - response := &pb.Response{Status: ccRespStatus, Payload: ccRespPayload} - result := []byte("res") - - mockRespFailure, err := protoutil.CreateProposalResponseFailure(prop.Header, prop.Payload, response, result, nil, "foo") - if err != nil { - return nil, fmt.Errorf("Could not create proposal response failure, err %s\n", err) - } - - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockRespFailure, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockDeliverClients := []pb.DeliverClient{getMockDeliverClientResponseWithTxStatusAndID(pb.TxValidationCode(mockRespFailure.Response.Status), "txid0")} - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - DeliverClients: mockDeliverClients, - } - return mockCF, nil -} - -func createCIS() *pb.ChaincodeInvocationSpec { - return &pb.ChaincodeInvocationSpec{ - ChaincodeSpec: &pb.ChaincodeSpec{ - Type: pb.ChaincodeSpec_GOLANG, - ChaincodeId: &pb.ChaincodeID{Name: "chaincode_name"}, - Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("arg1"), []byte("arg2")}}, - }, - } -} - -func getMockDeliverClientResponseWithTxStatusAndID(txStatus pb.TxValidationCode, txID string) *mock.PeerDeliverClient { - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { - return getMockDeliverConnectionResponseWithTxStatusAndID(txStatus, txID), nil - } - return mockDC -} - -func getMockDeliverConnectionResponseWithTxStatusAndID(txStatus pb.TxValidationCode, txID string) *mock.Deliver { - mockDF := &mock.Deliver{} - resp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_FilteredBlock{ - FilteredBlock: createFilteredBlock(txStatus, txID), - }, - } - mockDF.RecvReturns(resp, nil) - return mockDF -} - -func getMockDeliverClientRespondsWithFilteredBlocks(fb []*pb.FilteredBlock) *mock.PeerDeliverClient { - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { - mockDF := &mock.Deliver{} - for i, f := range fb { - resp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_FilteredBlock{ - FilteredBlock: f, - }, - } - mockDF.RecvReturnsOnCall(i, resp, nil) - } - return mockDF, nil - } - return mockDC -} - -func getMockDeliverClientRegisterAfterDelay(delayChan chan struct{}) *mock.PeerDeliverClient { - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { - mockDF := &mock.Deliver{} - mockDF.SendStub = func(*cb.Envelope) error { - <-delayChan - return nil - } - return mockDF, nil - } - return mockDC -} - -func getMockDeliverClientRespondAfterDelay(delayChan chan struct{}, txStatus pb.TxValidationCode, txID string) *mock.PeerDeliverClient { - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { - mockDF := &mock.Deliver{} - mockDF.RecvStub = func() (*pb.DeliverResponse, error) { - <-delayChan - resp := &pb.DeliverResponse{ - Type: &pb.DeliverResponse_FilteredBlock{ - FilteredBlock: createFilteredBlock(txStatus, txID), - }, - } - return resp, nil - } - return mockDF, nil - } - return mockDC -} - -func getMockDeliverClientWithErr(errMsg string) *mock.PeerDeliverClient { - mockDC := &mock.PeerDeliverClient{} - mockDC.DeliverFilteredStub = func(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverFilteredClient, error) { - return nil, fmt.Errorf(errMsg) - } - return mockDC -} - -func createFilteredBlock(txStatus pb.TxValidationCode, txIDs ...string) *pb.FilteredBlock { - var filteredTransactions []*pb.FilteredTransaction - for _, txID := range txIDs { - ft := &pb.FilteredTransaction{ - Txid: txID, - TxValidationCode: txStatus, - } - filteredTransactions = append(filteredTransactions, ft) - } - fb := &pb.FilteredBlock{ - Number: 0, - ChannelId: "testchannel", - FilteredTransactions: filteredTransactions, - } - return fb -} diff --git a/internal/peer/chaincode/list.go b/internal/peer/chaincode/list.go deleted file mode 100644 index 39287f607e4..00000000000 --- a/internal/peer/chaincode/list.go +++ /dev/null @@ -1,170 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "bytes" - "context" - "encoding/hex" - "fmt" - "reflect" - "strings" - - "github.com/golang/protobuf/proto" - cb "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/protoutil" - "github.com/pkg/errors" - "github.com/spf13/cobra" -) - -var ( - chaincodeListCmd *cobra.Command - getInstalledChaincodes bool - getInstantiatedChaincodes bool -) - -// listCmd returns the cobra command for listing -// the installed or instantiated chaincodes -func listCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeListCmd = &cobra.Command{ - Use: "list", - Short: "Get the instantiated chaincodes on a channel or installed chaincodes on a peer.", - Long: "Get the instantiated chaincodes in the channel if specify channel, or get installed chaincodes on the peer", - RunE: func(cmd *cobra.Command, args []string) error { - return getChaincodes(cmd, cf, cryptoProvider) - }, - } - - flagList := []string{ - "channelID", - "installed", - "instantiated", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - } - attachFlags(chaincodeListCmd, flagList) - - return chaincodeListCmd -} - -func getChaincodes(cmd *cobra.Command, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - if getInstantiatedChaincodes && channelID == "" { - return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") - } - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, false, cryptoProvider) - if err != nil { - return err - } - } - - creator, err := cf.Signer.Serialize() - if err != nil { - return fmt.Errorf("error serializing identity: %s", err) - } - - var proposal *pb.Proposal - - if getInstalledChaincodes == getInstantiatedChaincodes { - return errors.New("must explicitly specify \"--installed\" or \"--instantiated\"") - } - - if getInstalledChaincodes { - proposal, _, err = protoutil.CreateGetInstalledChaincodesProposal(creator) - } - - if getInstantiatedChaincodes { - proposal, _, err = protoutil.CreateGetChaincodesProposal(channelID, creator) - } - - if err != nil { - return errors.WithMessage(err, "error creating proposal") - } - - var signedProposal *pb.SignedProposal - signedProposal, err = protoutil.GetSignedProposal(proposal, cf.Signer) - if err != nil { - return errors.WithMessage(err, "error creating signed proposal") - } - - // list is currently only supported for one peer - proposalResponse, err := cf.EndorserClients[0].ProcessProposal(context.Background(), signedProposal) - if err != nil { - return errors.WithMessage(err, "error endorsing proposal") - } - - if proposalResponse.Response == nil { - return errors.Errorf("proposal response had nil response") - } - - if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) { - return errors.Errorf("bad response: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message) - } - - return printResponse(getInstalledChaincodes, getInstantiatedChaincodes, proposalResponse) -} - -// printResponse prints the information included in the response -// from the server. If getInstalledChaincodes is set to false, the -// proposal response will be interpreted as containing instantiated -// chaincode information. -func printResponse(getInstalledChaincodes, getInstantiatedChaincodes bool, proposalResponse *pb.ProposalResponse) error { - cqr := &pb.ChaincodeQueryResponse{} - err := proto.Unmarshal(proposalResponse.Response.Payload, cqr) - if err != nil { - return err - } - - if getInstalledChaincodes { - fmt.Println("Get installed chaincodes on peer:") - } else { - fmt.Printf("Get instantiated chaincodes on channel %s:\n", channelID) - } - - for _, chaincode := range cqr.Chaincodes { - fmt.Printf("%v\n", ccInfo{chaincode}.String()) - } - - return nil -} - -type ccInfo struct { - *pb.ChaincodeInfo -} - -func (cci ccInfo) String() string { - b := bytes.Buffer{} - md := reflect.ValueOf(*cci.ChaincodeInfo) - md2 := reflect.Indirect(reflect.ValueOf(*cci.ChaincodeInfo)).Type() - for i := 0; i < md.NumField(); i++ { - f := md.Field(i) - val := f.String() - if isBytes(f) { - val = hex.EncodeToString(f.Bytes()) - } - if len(val) == 0 { - continue - } - // Skip the proto-internal generated fields - if strings.HasPrefix(md2.Field(i).Name, "XXX") { - continue - } - b.WriteString(fmt.Sprintf("%s: %s, ", md2.Field(i).Name, val)) - } - return b.String()[:len(b.String())-2] -} - -func isBytes(v reflect.Value) bool { - return v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 -} diff --git a/internal/peer/chaincode/list_test.go b/internal/peer/chaincode/list_test.go deleted file mode 100644 index 56c5645ab22..00000000000 --- a/internal/peer/chaincode/list_test.go +++ /dev/null @@ -1,176 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "encoding/hex" - "fmt" - "testing" - - "github.com/golang/protobuf/proto" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/stretchr/testify/require" -) - -func TestChaincodeListCmd(t *testing.T) { - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %s", err) - } - - installedCqr := &pb.ChaincodeQueryResponse{ - Chaincodes: []*pb.ChaincodeInfo{ - {Name: "mycc1", Version: "1.0", Path: "codePath1", Input: "input", Escc: "escc", Vscc: "vscc", Id: []byte{1, 2, 3}}, - {Name: "mycc2", Version: "1.0", Path: "codePath2", Input: "input", Escc: "escc", Vscc: "vscc"}, - }, - } - installedCqrBytes, err := proto.Marshal(installedCqr) - if err != nil { - t.Fatalf("Marshal error: %s", err) - } - - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 200, Payload: installedCqrBytes}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - } - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - cmd := listCmd(mockCF, cryptoProvider) - - t.Run("get installed chaincodes - lscc", func(t *testing.T) { - resetFlags() - - args := []string{"--installed"} - cmd.SetArgs(args) - if err := cmd.Execute(); err != nil { - t.Errorf("Run chaincode list cmd to get installed chaincodes error:%v", err) - } - }) - - t.Run("get instantiated chaincodes - no channel", func(t *testing.T) { - resetFlags() - - args := []string{"--instantiated"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "Run chaincode list cmd to get instantiated chaincodes should fail if invoked without -C flag") - }) - - t.Run("get instantiated chaincodes - no channel", func(t *testing.T) { - resetFlags() - - args := []string{"--instantiated"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "Run chaincode list cmd to get instantiated chaincodes should fail if invoked without -C flag") - }) - - t.Run("get instantiated chaincodes - success", func(t *testing.T) { - resetFlags() - instantiatedChaincodesCmd := listCmd(mockCF, cryptoProvider) - args := []string{"--instantiated", "-C", "mychannel"} - instantiatedChaincodesCmd.SetArgs(args) - if err := instantiatedChaincodesCmd.Execute(); err != nil { - t.Errorf("Run chaincode list cmd to get instantiated chaincodes error:%v", err) - } - }) - - t.Run("both --installed and --instantiated set - no channel", func(t *testing.T) { - resetFlags() - - // Wrong case: Set both "--installed" and "--instantiated" - cmd = listCmd(mockCF, cryptoProvider) - args := []string{"--installed", "--instantiated"} - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "Run chaincode list cmd to get instantiated/installed chaincodes should fail if invoked without -C flag") - }) - - t.Run("both --installed and --instantiated set - no channel", func(t *testing.T) { - resetFlags() - args := []string{"--installed", "--instantiated", "-C", "mychannel"} - cmd.SetArgs(args) - expectErr := fmt.Errorf("must explicitly specify \"--installed\" or \"--instantiated\"") - err = cmd.Execute() - require.Error(t, err) - require.Equal(t, expectErr.Error(), err.Error()) - }) - - t.Run("neither --installed nor --instantiated set", func(t *testing.T) { - resetFlags() - args := []string{"-C", "mychannel"} - cmd.SetArgs(args) - - expectErr := fmt.Errorf("must explicitly specify \"--installed\" or \"--instantiated\"") - err = cmd.Execute() - require.Error(t, err) - require.Equal(t, expectErr.Error(), err.Error()) - }) -} - -func TestChaincodeListFailure(t *testing.T) { - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %s", err) - } - - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 500, Message: "error message"}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - } - - // reset channelID, it might have been set by previous test - channelID = "" - - resetFlags() - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - // Get instantiated chaincodes - instantiatedChaincodesCmd := listCmd(mockCF, cryptoProvider) - args := []string{"--instantiated", "-C", "mychannel"} - instantiatedChaincodesCmd.SetArgs(args) - err = instantiatedChaincodesCmd.Execute() - require.Error(t, err) - require.Regexp(t, "bad response: 500 - error message", err.Error()) -} - -func TestString(t *testing.T) { - id := []byte{1, 2, 3, 4, 5} - idBytes := hex.EncodeToString(id) - b, _ := hex.DecodeString(idBytes) - ccInf := &ccInfo{ - ChaincodeInfo: &pb.ChaincodeInfo{ - Name: "ccName", - Id: b, - Version: "1.0", - Escc: "escc", - Input: "input", - Vscc: "vscc", - }, - } - require.Equal(t, "Name: ccName, Version: 1.0, Input: input, Escc: escc, Vscc: vscc, Id: 0102030405", ccInf.String()) -} diff --git a/internal/peer/chaincode/mock/deliver.go b/internal/peer/chaincode/mock/deliver.go deleted file mode 100644 index 5d1a5e3c37e..00000000000 --- a/internal/peer/chaincode/mock/deliver.go +++ /dev/null @@ -1,587 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mock - -import ( - "context" - "sync" - - "github.com/hyperledger/fabric-protos-go/common" - "github.com/hyperledger/fabric-protos-go/peer" - "google.golang.org/grpc/metadata" -) - -type Deliver struct { - CloseSendStub func() error - closeSendMutex sync.RWMutex - closeSendArgsForCall []struct { - } - closeSendReturns struct { - result1 error - } - closeSendReturnsOnCall map[int]struct { - result1 error - } - ContextStub func() context.Context - contextMutex sync.RWMutex - contextArgsForCall []struct { - } - contextReturns struct { - result1 context.Context - } - contextReturnsOnCall map[int]struct { - result1 context.Context - } - HeaderStub func() (metadata.MD, error) - headerMutex sync.RWMutex - headerArgsForCall []struct { - } - headerReturns struct { - result1 metadata.MD - result2 error - } - headerReturnsOnCall map[int]struct { - result1 metadata.MD - result2 error - } - RecvStub func() (*peer.DeliverResponse, error) - recvMutex sync.RWMutex - recvArgsForCall []struct { - } - recvReturns struct { - result1 *peer.DeliverResponse - result2 error - } - recvReturnsOnCall map[int]struct { - result1 *peer.DeliverResponse - result2 error - } - RecvMsgStub func(interface{}) error - recvMsgMutex sync.RWMutex - recvMsgArgsForCall []struct { - arg1 interface{} - } - recvMsgReturns struct { - result1 error - } - recvMsgReturnsOnCall map[int]struct { - result1 error - } - SendStub func(*common.Envelope) error - sendMutex sync.RWMutex - sendArgsForCall []struct { - arg1 *common.Envelope - } - sendReturns struct { - result1 error - } - sendReturnsOnCall map[int]struct { - result1 error - } - SendMsgStub func(interface{}) error - sendMsgMutex sync.RWMutex - sendMsgArgsForCall []struct { - arg1 interface{} - } - sendMsgReturns struct { - result1 error - } - sendMsgReturnsOnCall map[int]struct { - result1 error - } - TrailerStub func() metadata.MD - trailerMutex sync.RWMutex - trailerArgsForCall []struct { - } - trailerReturns struct { - result1 metadata.MD - } - trailerReturnsOnCall map[int]struct { - result1 metadata.MD - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *Deliver) CloseSend() error { - fake.closeSendMutex.Lock() - ret, specificReturn := fake.closeSendReturnsOnCall[len(fake.closeSendArgsForCall)] - fake.closeSendArgsForCall = append(fake.closeSendArgsForCall, struct { - }{}) - fake.recordInvocation("CloseSend", []interface{}{}) - fake.closeSendMutex.Unlock() - if fake.CloseSendStub != nil { - return fake.CloseSendStub() - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.closeSendReturns - return fakeReturns.result1 -} - -func (fake *Deliver) CloseSendCallCount() int { - fake.closeSendMutex.RLock() - defer fake.closeSendMutex.RUnlock() - return len(fake.closeSendArgsForCall) -} - -func (fake *Deliver) CloseSendCalls(stub func() error) { - fake.closeSendMutex.Lock() - defer fake.closeSendMutex.Unlock() - fake.CloseSendStub = stub -} - -func (fake *Deliver) CloseSendReturns(result1 error) { - fake.closeSendMutex.Lock() - defer fake.closeSendMutex.Unlock() - fake.CloseSendStub = nil - fake.closeSendReturns = struct { - result1 error - }{result1} -} - -func (fake *Deliver) CloseSendReturnsOnCall(i int, result1 error) { - fake.closeSendMutex.Lock() - defer fake.closeSendMutex.Unlock() - fake.CloseSendStub = nil - if fake.closeSendReturnsOnCall == nil { - fake.closeSendReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.closeSendReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *Deliver) Context() context.Context { - fake.contextMutex.Lock() - ret, specificReturn := fake.contextReturnsOnCall[len(fake.contextArgsForCall)] - fake.contextArgsForCall = append(fake.contextArgsForCall, struct { - }{}) - fake.recordInvocation("Context", []interface{}{}) - fake.contextMutex.Unlock() - if fake.ContextStub != nil { - return fake.ContextStub() - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.contextReturns - return fakeReturns.result1 -} - -func (fake *Deliver) ContextCallCount() int { - fake.contextMutex.RLock() - defer fake.contextMutex.RUnlock() - return len(fake.contextArgsForCall) -} - -func (fake *Deliver) ContextCalls(stub func() context.Context) { - fake.contextMutex.Lock() - defer fake.contextMutex.Unlock() - fake.ContextStub = stub -} - -func (fake *Deliver) ContextReturns(result1 context.Context) { - fake.contextMutex.Lock() - defer fake.contextMutex.Unlock() - fake.ContextStub = nil - fake.contextReturns = struct { - result1 context.Context - }{result1} -} - -func (fake *Deliver) ContextReturnsOnCall(i int, result1 context.Context) { - fake.contextMutex.Lock() - defer fake.contextMutex.Unlock() - fake.ContextStub = nil - if fake.contextReturnsOnCall == nil { - fake.contextReturnsOnCall = make(map[int]struct { - result1 context.Context - }) - } - fake.contextReturnsOnCall[i] = struct { - result1 context.Context - }{result1} -} - -func (fake *Deliver) Header() (metadata.MD, error) { - fake.headerMutex.Lock() - ret, specificReturn := fake.headerReturnsOnCall[len(fake.headerArgsForCall)] - fake.headerArgsForCall = append(fake.headerArgsForCall, struct { - }{}) - fake.recordInvocation("Header", []interface{}{}) - fake.headerMutex.Unlock() - if fake.HeaderStub != nil { - return fake.HeaderStub() - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.headerReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *Deliver) HeaderCallCount() int { - fake.headerMutex.RLock() - defer fake.headerMutex.RUnlock() - return len(fake.headerArgsForCall) -} - -func (fake *Deliver) HeaderCalls(stub func() (metadata.MD, error)) { - fake.headerMutex.Lock() - defer fake.headerMutex.Unlock() - fake.HeaderStub = stub -} - -func (fake *Deliver) HeaderReturns(result1 metadata.MD, result2 error) { - fake.headerMutex.Lock() - defer fake.headerMutex.Unlock() - fake.HeaderStub = nil - fake.headerReturns = struct { - result1 metadata.MD - result2 error - }{result1, result2} -} - -func (fake *Deliver) HeaderReturnsOnCall(i int, result1 metadata.MD, result2 error) { - fake.headerMutex.Lock() - defer fake.headerMutex.Unlock() - fake.HeaderStub = nil - if fake.headerReturnsOnCall == nil { - fake.headerReturnsOnCall = make(map[int]struct { - result1 metadata.MD - result2 error - }) - } - fake.headerReturnsOnCall[i] = struct { - result1 metadata.MD - result2 error - }{result1, result2} -} - -func (fake *Deliver) Recv() (*peer.DeliverResponse, error) { - fake.recvMutex.Lock() - ret, specificReturn := fake.recvReturnsOnCall[len(fake.recvArgsForCall)] - fake.recvArgsForCall = append(fake.recvArgsForCall, struct { - }{}) - fake.recordInvocation("Recv", []interface{}{}) - fake.recvMutex.Unlock() - if fake.RecvStub != nil { - return fake.RecvStub() - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.recvReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *Deliver) RecvCallCount() int { - fake.recvMutex.RLock() - defer fake.recvMutex.RUnlock() - return len(fake.recvArgsForCall) -} - -func (fake *Deliver) RecvCalls(stub func() (*peer.DeliverResponse, error)) { - fake.recvMutex.Lock() - defer fake.recvMutex.Unlock() - fake.RecvStub = stub -} - -func (fake *Deliver) RecvReturns(result1 *peer.DeliverResponse, result2 error) { - fake.recvMutex.Lock() - defer fake.recvMutex.Unlock() - fake.RecvStub = nil - fake.recvReturns = struct { - result1 *peer.DeliverResponse - result2 error - }{result1, result2} -} - -func (fake *Deliver) RecvReturnsOnCall(i int, result1 *peer.DeliverResponse, result2 error) { - fake.recvMutex.Lock() - defer fake.recvMutex.Unlock() - fake.RecvStub = nil - if fake.recvReturnsOnCall == nil { - fake.recvReturnsOnCall = make(map[int]struct { - result1 *peer.DeliverResponse - result2 error - }) - } - fake.recvReturnsOnCall[i] = struct { - result1 *peer.DeliverResponse - result2 error - }{result1, result2} -} - -func (fake *Deliver) RecvMsg(arg1 interface{}) error { - fake.recvMsgMutex.Lock() - ret, specificReturn := fake.recvMsgReturnsOnCall[len(fake.recvMsgArgsForCall)] - fake.recvMsgArgsForCall = append(fake.recvMsgArgsForCall, struct { - arg1 interface{} - }{arg1}) - fake.recordInvocation("RecvMsg", []interface{}{arg1}) - fake.recvMsgMutex.Unlock() - if fake.RecvMsgStub != nil { - return fake.RecvMsgStub(arg1) - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.recvMsgReturns - return fakeReturns.result1 -} - -func (fake *Deliver) RecvMsgCallCount() int { - fake.recvMsgMutex.RLock() - defer fake.recvMsgMutex.RUnlock() - return len(fake.recvMsgArgsForCall) -} - -func (fake *Deliver) RecvMsgCalls(stub func(interface{}) error) { - fake.recvMsgMutex.Lock() - defer fake.recvMsgMutex.Unlock() - fake.RecvMsgStub = stub -} - -func (fake *Deliver) RecvMsgArgsForCall(i int) interface{} { - fake.recvMsgMutex.RLock() - defer fake.recvMsgMutex.RUnlock() - argsForCall := fake.recvMsgArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *Deliver) RecvMsgReturns(result1 error) { - fake.recvMsgMutex.Lock() - defer fake.recvMsgMutex.Unlock() - fake.RecvMsgStub = nil - fake.recvMsgReturns = struct { - result1 error - }{result1} -} - -func (fake *Deliver) RecvMsgReturnsOnCall(i int, result1 error) { - fake.recvMsgMutex.Lock() - defer fake.recvMsgMutex.Unlock() - fake.RecvMsgStub = nil - if fake.recvMsgReturnsOnCall == nil { - fake.recvMsgReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.recvMsgReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *Deliver) Send(arg1 *common.Envelope) error { - fake.sendMutex.Lock() - ret, specificReturn := fake.sendReturnsOnCall[len(fake.sendArgsForCall)] - fake.sendArgsForCall = append(fake.sendArgsForCall, struct { - arg1 *common.Envelope - }{arg1}) - fake.recordInvocation("Send", []interface{}{arg1}) - fake.sendMutex.Unlock() - if fake.SendStub != nil { - return fake.SendStub(arg1) - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.sendReturns - return fakeReturns.result1 -} - -func (fake *Deliver) SendCallCount() int { - fake.sendMutex.RLock() - defer fake.sendMutex.RUnlock() - return len(fake.sendArgsForCall) -} - -func (fake *Deliver) SendCalls(stub func(*common.Envelope) error) { - fake.sendMutex.Lock() - defer fake.sendMutex.Unlock() - fake.SendStub = stub -} - -func (fake *Deliver) SendArgsForCall(i int) *common.Envelope { - fake.sendMutex.RLock() - defer fake.sendMutex.RUnlock() - argsForCall := fake.sendArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *Deliver) SendReturns(result1 error) { - fake.sendMutex.Lock() - defer fake.sendMutex.Unlock() - fake.SendStub = nil - fake.sendReturns = struct { - result1 error - }{result1} -} - -func (fake *Deliver) SendReturnsOnCall(i int, result1 error) { - fake.sendMutex.Lock() - defer fake.sendMutex.Unlock() - fake.SendStub = nil - if fake.sendReturnsOnCall == nil { - fake.sendReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.sendReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *Deliver) SendMsg(arg1 interface{}) error { - fake.sendMsgMutex.Lock() - ret, specificReturn := fake.sendMsgReturnsOnCall[len(fake.sendMsgArgsForCall)] - fake.sendMsgArgsForCall = append(fake.sendMsgArgsForCall, struct { - arg1 interface{} - }{arg1}) - fake.recordInvocation("SendMsg", []interface{}{arg1}) - fake.sendMsgMutex.Unlock() - if fake.SendMsgStub != nil { - return fake.SendMsgStub(arg1) - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.sendMsgReturns - return fakeReturns.result1 -} - -func (fake *Deliver) SendMsgCallCount() int { - fake.sendMsgMutex.RLock() - defer fake.sendMsgMutex.RUnlock() - return len(fake.sendMsgArgsForCall) -} - -func (fake *Deliver) SendMsgCalls(stub func(interface{}) error) { - fake.sendMsgMutex.Lock() - defer fake.sendMsgMutex.Unlock() - fake.SendMsgStub = stub -} - -func (fake *Deliver) SendMsgArgsForCall(i int) interface{} { - fake.sendMsgMutex.RLock() - defer fake.sendMsgMutex.RUnlock() - argsForCall := fake.sendMsgArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *Deliver) SendMsgReturns(result1 error) { - fake.sendMsgMutex.Lock() - defer fake.sendMsgMutex.Unlock() - fake.SendMsgStub = nil - fake.sendMsgReturns = struct { - result1 error - }{result1} -} - -func (fake *Deliver) SendMsgReturnsOnCall(i int, result1 error) { - fake.sendMsgMutex.Lock() - defer fake.sendMsgMutex.Unlock() - fake.SendMsgStub = nil - if fake.sendMsgReturnsOnCall == nil { - fake.sendMsgReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.sendMsgReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *Deliver) Trailer() metadata.MD { - fake.trailerMutex.Lock() - ret, specificReturn := fake.trailerReturnsOnCall[len(fake.trailerArgsForCall)] - fake.trailerArgsForCall = append(fake.trailerArgsForCall, struct { - }{}) - fake.recordInvocation("Trailer", []interface{}{}) - fake.trailerMutex.Unlock() - if fake.TrailerStub != nil { - return fake.TrailerStub() - } - if specificReturn { - return ret.result1 - } - fakeReturns := fake.trailerReturns - return fakeReturns.result1 -} - -func (fake *Deliver) TrailerCallCount() int { - fake.trailerMutex.RLock() - defer fake.trailerMutex.RUnlock() - return len(fake.trailerArgsForCall) -} - -func (fake *Deliver) TrailerCalls(stub func() metadata.MD) { - fake.trailerMutex.Lock() - defer fake.trailerMutex.Unlock() - fake.TrailerStub = stub -} - -func (fake *Deliver) TrailerReturns(result1 metadata.MD) { - fake.trailerMutex.Lock() - defer fake.trailerMutex.Unlock() - fake.TrailerStub = nil - fake.trailerReturns = struct { - result1 metadata.MD - }{result1} -} - -func (fake *Deliver) TrailerReturnsOnCall(i int, result1 metadata.MD) { - fake.trailerMutex.Lock() - defer fake.trailerMutex.Unlock() - fake.TrailerStub = nil - if fake.trailerReturnsOnCall == nil { - fake.trailerReturnsOnCall = make(map[int]struct { - result1 metadata.MD - }) - } - fake.trailerReturnsOnCall[i] = struct { - result1 metadata.MD - }{result1} -} - -func (fake *Deliver) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.closeSendMutex.RLock() - defer fake.closeSendMutex.RUnlock() - fake.contextMutex.RLock() - defer fake.contextMutex.RUnlock() - fake.headerMutex.RLock() - defer fake.headerMutex.RUnlock() - fake.recvMutex.RLock() - defer fake.recvMutex.RUnlock() - fake.recvMsgMutex.RLock() - defer fake.recvMsgMutex.RUnlock() - fake.sendMutex.RLock() - defer fake.sendMutex.RUnlock() - fake.sendMsgMutex.RLock() - defer fake.sendMsgMutex.RUnlock() - fake.trailerMutex.RLock() - defer fake.trailerMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *Deliver) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/internal/peer/chaincode/mock/deliver_client.go b/internal/peer/chaincode/mock/deliver_client.go deleted file mode 100644 index 7f6dc4d391a..00000000000 --- a/internal/peer/chaincode/mock/deliver_client.go +++ /dev/null @@ -1,277 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mock - -import ( - "context" - "sync" - - "github.com/hyperledger/fabric-protos-go/peer" - "google.golang.org/grpc" -) - -type PeerDeliverClient struct { - DeliverStub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverClient, error) - deliverMutex sync.RWMutex - deliverArgsForCall []struct { - arg1 context.Context - arg2 []grpc.CallOption - } - deliverReturns struct { - result1 peer.Deliver_DeliverClient - result2 error - } - deliverReturnsOnCall map[int]struct { - result1 peer.Deliver_DeliverClient - result2 error - } - DeliverFilteredStub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverFilteredClient, error) - deliverFilteredMutex sync.RWMutex - deliverFilteredArgsForCall []struct { - arg1 context.Context - arg2 []grpc.CallOption - } - deliverFilteredReturns struct { - result1 peer.Deliver_DeliverFilteredClient - result2 error - } - deliverFilteredReturnsOnCall map[int]struct { - result1 peer.Deliver_DeliverFilteredClient - result2 error - } - DeliverWithPrivateDataStub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverWithPrivateDataClient, error) - deliverWithPrivateDataMutex sync.RWMutex - deliverWithPrivateDataArgsForCall []struct { - arg1 context.Context - arg2 []grpc.CallOption - } - deliverWithPrivateDataReturns struct { - result1 peer.Deliver_DeliverWithPrivateDataClient - result2 error - } - deliverWithPrivateDataReturnsOnCall map[int]struct { - result1 peer.Deliver_DeliverWithPrivateDataClient - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *PeerDeliverClient) Deliver(arg1 context.Context, arg2 ...grpc.CallOption) (peer.Deliver_DeliverClient, error) { - fake.deliverMutex.Lock() - ret, specificReturn := fake.deliverReturnsOnCall[len(fake.deliverArgsForCall)] - fake.deliverArgsForCall = append(fake.deliverArgsForCall, struct { - arg1 context.Context - arg2 []grpc.CallOption - }{arg1, arg2}) - fake.recordInvocation("Deliver", []interface{}{arg1, arg2}) - fake.deliverMutex.Unlock() - if fake.DeliverStub != nil { - return fake.DeliverStub(arg1, arg2...) - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.deliverReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *PeerDeliverClient) DeliverCallCount() int { - fake.deliverMutex.RLock() - defer fake.deliverMutex.RUnlock() - return len(fake.deliverArgsForCall) -} - -func (fake *PeerDeliverClient) DeliverCalls(stub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverClient, error)) { - fake.deliverMutex.Lock() - defer fake.deliverMutex.Unlock() - fake.DeliverStub = stub -} - -func (fake *PeerDeliverClient) DeliverArgsForCall(i int) (context.Context, []grpc.CallOption) { - fake.deliverMutex.RLock() - defer fake.deliverMutex.RUnlock() - argsForCall := fake.deliverArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *PeerDeliverClient) DeliverReturns(result1 peer.Deliver_DeliverClient, result2 error) { - fake.deliverMutex.Lock() - defer fake.deliverMutex.Unlock() - fake.DeliverStub = nil - fake.deliverReturns = struct { - result1 peer.Deliver_DeliverClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) DeliverReturnsOnCall(i int, result1 peer.Deliver_DeliverClient, result2 error) { - fake.deliverMutex.Lock() - defer fake.deliverMutex.Unlock() - fake.DeliverStub = nil - if fake.deliverReturnsOnCall == nil { - fake.deliverReturnsOnCall = make(map[int]struct { - result1 peer.Deliver_DeliverClient - result2 error - }) - } - fake.deliverReturnsOnCall[i] = struct { - result1 peer.Deliver_DeliverClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) DeliverFiltered(arg1 context.Context, arg2 ...grpc.CallOption) (peer.Deliver_DeliverFilteredClient, error) { - fake.deliverFilteredMutex.Lock() - ret, specificReturn := fake.deliverFilteredReturnsOnCall[len(fake.deliverFilteredArgsForCall)] - fake.deliverFilteredArgsForCall = append(fake.deliverFilteredArgsForCall, struct { - arg1 context.Context - arg2 []grpc.CallOption - }{arg1, arg2}) - fake.recordInvocation("DeliverFiltered", []interface{}{arg1, arg2}) - fake.deliverFilteredMutex.Unlock() - if fake.DeliverFilteredStub != nil { - return fake.DeliverFilteredStub(arg1, arg2...) - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.deliverFilteredReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *PeerDeliverClient) DeliverFilteredCallCount() int { - fake.deliverFilteredMutex.RLock() - defer fake.deliverFilteredMutex.RUnlock() - return len(fake.deliverFilteredArgsForCall) -} - -func (fake *PeerDeliverClient) DeliverFilteredCalls(stub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverFilteredClient, error)) { - fake.deliverFilteredMutex.Lock() - defer fake.deliverFilteredMutex.Unlock() - fake.DeliverFilteredStub = stub -} - -func (fake *PeerDeliverClient) DeliverFilteredArgsForCall(i int) (context.Context, []grpc.CallOption) { - fake.deliverFilteredMutex.RLock() - defer fake.deliverFilteredMutex.RUnlock() - argsForCall := fake.deliverFilteredArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *PeerDeliverClient) DeliverFilteredReturns(result1 peer.Deliver_DeliverFilteredClient, result2 error) { - fake.deliverFilteredMutex.Lock() - defer fake.deliverFilteredMutex.Unlock() - fake.DeliverFilteredStub = nil - fake.deliverFilteredReturns = struct { - result1 peer.Deliver_DeliverFilteredClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) DeliverFilteredReturnsOnCall(i int, result1 peer.Deliver_DeliverFilteredClient, result2 error) { - fake.deliverFilteredMutex.Lock() - defer fake.deliverFilteredMutex.Unlock() - fake.DeliverFilteredStub = nil - if fake.deliverFilteredReturnsOnCall == nil { - fake.deliverFilteredReturnsOnCall = make(map[int]struct { - result1 peer.Deliver_DeliverFilteredClient - result2 error - }) - } - fake.deliverFilteredReturnsOnCall[i] = struct { - result1 peer.Deliver_DeliverFilteredClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) DeliverWithPrivateData(arg1 context.Context, arg2 ...grpc.CallOption) (peer.Deliver_DeliverWithPrivateDataClient, error) { - fake.deliverWithPrivateDataMutex.Lock() - ret, specificReturn := fake.deliverWithPrivateDataReturnsOnCall[len(fake.deliverWithPrivateDataArgsForCall)] - fake.deliverWithPrivateDataArgsForCall = append(fake.deliverWithPrivateDataArgsForCall, struct { - arg1 context.Context - arg2 []grpc.CallOption - }{arg1, arg2}) - fake.recordInvocation("DeliverWithPrivateData", []interface{}{arg1, arg2}) - fake.deliverWithPrivateDataMutex.Unlock() - if fake.DeliverWithPrivateDataStub != nil { - return fake.DeliverWithPrivateDataStub(arg1, arg2...) - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.deliverWithPrivateDataReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *PeerDeliverClient) DeliverWithPrivateDataCallCount() int { - fake.deliverWithPrivateDataMutex.RLock() - defer fake.deliverWithPrivateDataMutex.RUnlock() - return len(fake.deliverWithPrivateDataArgsForCall) -} - -func (fake *PeerDeliverClient) DeliverWithPrivateDataCalls(stub func(context.Context, ...grpc.CallOption) (peer.Deliver_DeliverWithPrivateDataClient, error)) { - fake.deliverWithPrivateDataMutex.Lock() - defer fake.deliverWithPrivateDataMutex.Unlock() - fake.DeliverWithPrivateDataStub = stub -} - -func (fake *PeerDeliverClient) DeliverWithPrivateDataArgsForCall(i int) (context.Context, []grpc.CallOption) { - fake.deliverWithPrivateDataMutex.RLock() - defer fake.deliverWithPrivateDataMutex.RUnlock() - argsForCall := fake.deliverWithPrivateDataArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *PeerDeliverClient) DeliverWithPrivateDataReturns(result1 peer.Deliver_DeliverWithPrivateDataClient, result2 error) { - fake.deliverWithPrivateDataMutex.Lock() - defer fake.deliverWithPrivateDataMutex.Unlock() - fake.DeliverWithPrivateDataStub = nil - fake.deliverWithPrivateDataReturns = struct { - result1 peer.Deliver_DeliverWithPrivateDataClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) DeliverWithPrivateDataReturnsOnCall(i int, result1 peer.Deliver_DeliverWithPrivateDataClient, result2 error) { - fake.deliverWithPrivateDataMutex.Lock() - defer fake.deliverWithPrivateDataMutex.Unlock() - fake.DeliverWithPrivateDataStub = nil - if fake.deliverWithPrivateDataReturnsOnCall == nil { - fake.deliverWithPrivateDataReturnsOnCall = make(map[int]struct { - result1 peer.Deliver_DeliverWithPrivateDataClient - result2 error - }) - } - fake.deliverWithPrivateDataReturnsOnCall[i] = struct { - result1 peer.Deliver_DeliverWithPrivateDataClient - result2 error - }{result1, result2} -} - -func (fake *PeerDeliverClient) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.deliverMutex.RLock() - defer fake.deliverMutex.RUnlock() - fake.deliverFilteredMutex.RLock() - defer fake.deliverFilteredMutex.RUnlock() - fake.deliverWithPrivateDataMutex.RLock() - defer fake.deliverWithPrivateDataMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *PeerDeliverClient) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/internal/peer/chaincode/mock/signer_serializer.go b/internal/peer/chaincode/mock/signer_serializer.go deleted file mode 100644 index 577c415348b..00000000000 --- a/internal/peer/chaincode/mock/signer_serializer.go +++ /dev/null @@ -1,185 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mock - -import ( - "sync" -) - -type SignerSerializer struct { - SerializeStub func() ([]byte, error) - serializeMutex sync.RWMutex - serializeArgsForCall []struct { - } - serializeReturns struct { - result1 []byte - result2 error - } - serializeReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - SignStub func([]byte) ([]byte, error) - signMutex sync.RWMutex - signArgsForCall []struct { - arg1 []byte - } - signReturns struct { - result1 []byte - result2 error - } - signReturnsOnCall map[int]struct { - result1 []byte - result2 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *SignerSerializer) Serialize() ([]byte, error) { - fake.serializeMutex.Lock() - ret, specificReturn := fake.serializeReturnsOnCall[len(fake.serializeArgsForCall)] - fake.serializeArgsForCall = append(fake.serializeArgsForCall, struct { - }{}) - fake.recordInvocation("Serialize", []interface{}{}) - fake.serializeMutex.Unlock() - if fake.SerializeStub != nil { - return fake.SerializeStub() - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.serializeReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SignerSerializer) SerializeCallCount() int { - fake.serializeMutex.RLock() - defer fake.serializeMutex.RUnlock() - return len(fake.serializeArgsForCall) -} - -func (fake *SignerSerializer) SerializeCalls(stub func() ([]byte, error)) { - fake.serializeMutex.Lock() - defer fake.serializeMutex.Unlock() - fake.SerializeStub = stub -} - -func (fake *SignerSerializer) SerializeReturns(result1 []byte, result2 error) { - fake.serializeMutex.Lock() - defer fake.serializeMutex.Unlock() - fake.SerializeStub = nil - fake.serializeReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *SignerSerializer) SerializeReturnsOnCall(i int, result1 []byte, result2 error) { - fake.serializeMutex.Lock() - defer fake.serializeMutex.Unlock() - fake.SerializeStub = nil - if fake.serializeReturnsOnCall == nil { - fake.serializeReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.serializeReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *SignerSerializer) Sign(arg1 []byte) ([]byte, error) { - var arg1Copy []byte - if arg1 != nil { - arg1Copy = make([]byte, len(arg1)) - copy(arg1Copy, arg1) - } - fake.signMutex.Lock() - ret, specificReturn := fake.signReturnsOnCall[len(fake.signArgsForCall)] - fake.signArgsForCall = append(fake.signArgsForCall, struct { - arg1 []byte - }{arg1Copy}) - fake.recordInvocation("Sign", []interface{}{arg1Copy}) - fake.signMutex.Unlock() - if fake.SignStub != nil { - return fake.SignStub(arg1) - } - if specificReturn { - return ret.result1, ret.result2 - } - fakeReturns := fake.signReturns - return fakeReturns.result1, fakeReturns.result2 -} - -func (fake *SignerSerializer) SignCallCount() int { - fake.signMutex.RLock() - defer fake.signMutex.RUnlock() - return len(fake.signArgsForCall) -} - -func (fake *SignerSerializer) SignCalls(stub func([]byte) ([]byte, error)) { - fake.signMutex.Lock() - defer fake.signMutex.Unlock() - fake.SignStub = stub -} - -func (fake *SignerSerializer) SignArgsForCall(i int) []byte { - fake.signMutex.RLock() - defer fake.signMutex.RUnlock() - argsForCall := fake.signArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *SignerSerializer) SignReturns(result1 []byte, result2 error) { - fake.signMutex.Lock() - defer fake.signMutex.Unlock() - fake.SignStub = nil - fake.signReturns = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *SignerSerializer) SignReturnsOnCall(i int, result1 []byte, result2 error) { - fake.signMutex.Lock() - defer fake.signMutex.Unlock() - fake.SignStub = nil - if fake.signReturnsOnCall == nil { - fake.signReturnsOnCall = make(map[int]struct { - result1 []byte - result2 error - }) - } - fake.signReturnsOnCall[i] = struct { - result1 []byte - result2 error - }{result1, result2} -} - -func (fake *SignerSerializer) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.serializeMutex.RLock() - defer fake.serializeMutex.RUnlock() - fake.signMutex.RLock() - defer fake.signMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *SignerSerializer) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/internal/peer/chaincode/package.go b/internal/peer/chaincode/package.go deleted file mode 100644 index b6a23eed59e..00000000000 --- a/internal/peer/chaincode/package.go +++ /dev/null @@ -1,225 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "os" - - "github.com/golang/protobuf/proto" - pcommon "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/factory" - "github.com/hyperledger/fabric/common/policydsl" - "github.com/hyperledger/fabric/core/common/ccpackage" - "github.com/hyperledger/fabric/internal/pkg/identity" - mspmgmt "github.com/hyperledger/fabric/msp/mgmt" - "github.com/hyperledger/fabric/protoutil" - "github.com/pkg/errors" - "github.com/spf13/cobra" -) - -var ( - chaincodePackageCmd *cobra.Command - createSignedCCDepSpec bool - signCCDepSpec bool - instantiationPolicy string -) - -const packageCmdName = "package" - -type ccDepSpecFactory func(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) - -func defaultCDSFactory(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) { - return getChaincodeDeploymentSpec(spec, true) -} - -// Packager holds the dependencies needed to package -// a chaincode and write it -type Packager struct { - CDSFactory ccDepSpecFactory - ChaincodeCmdFactory *ChaincodeCmdFactory - Command *cobra.Command - Input *PackageInput - CryptoProvider bccsp.BCCSP -} - -// PackageInput holds the input parameters for packaging a -// ChaincodeInstallPackage -type PackageInput struct { - Name string - Version string - InstantiationPolicy string - CreateSignedCCDepSpec bool - SignCCDepSpec bool - OutputFile string - Path string - Type string -} - -// packageCmd returns the cobra command for packaging chaincode -func packageCmd(cf *ChaincodeCmdFactory, cdsFact ccDepSpecFactory, p *Packager, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodePackageCmd = &cobra.Command{ - Use: "package [outputfile]", - Short: "Package a chaincode", - Long: "Package a chaincode and write the package to a file.", - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - if p == nil { - // UT will supply its own mock factory - if cdsFact == nil { - cdsFact = defaultCDSFactory - } - p = &Packager{ - CDSFactory: cdsFact, - ChaincodeCmdFactory: cf, - CryptoProvider: cryptoProvider, - } - } - p.Command = cmd - - return p.packageChaincode(args) - }, - } - flagList := []string{ - "lang", - "path", - "ctor", - "name", - "version", - "cc-package", - "sign", - "instantiate-policy", - } - attachFlags(chaincodePackageCmd, flagList) - - return chaincodePackageCmd -} - -// packageChaincode packages the chaincode. -func (p *Packager) packageChaincode(args []string) error { - if p.Command != nil { - // Parsing of the command line is done so silence cmd usage - p.Command.SilenceUsage = true - } - - if len(args) != 1 { - return errors.New("output file not specified or invalid number of args (filename should be the only arg)") - } - p.setInput(args[0]) - - // LSCC package - return p.packageCC() -} - -func (p *Packager) setInput(outputFile string) { - p.Input = &PackageInput{ - Name: chaincodeName, - Version: chaincodeVersion, - InstantiationPolicy: instantiationPolicy, - CreateSignedCCDepSpec: createSignedCCDepSpec, - SignCCDepSpec: signCCDepSpec, - OutputFile: outputFile, - Path: chaincodePath, - Type: chaincodeLang, - } -} - -// packageCC creates the LSCC chaincode packages -// (ChaincodeDeploymentSpec and SignedChaincodeDeploymentSpec) -func (p *Packager) packageCC() error { - if p.CDSFactory == nil { - return errors.New("chaincode deployment spec factory not specified") - } - - var err error - if p.ChaincodeCmdFactory == nil { - p.ChaincodeCmdFactory, err = InitCmdFactory(p.Command.Name(), false, false, p.CryptoProvider) - if err != nil { - return err - } - } - spec, err := getChaincodeSpec(p.Command) - if err != nil { - return err - } - - cds, err := p.CDSFactory(spec) - if err != nil { - return errors.WithMessagef(err, "error getting chaincode code %s", p.Input.Name) - } - - var bytesToWrite []byte - if createSignedCCDepSpec { - bytesToWrite, err = getChaincodeInstallPackage(cds, p.ChaincodeCmdFactory) - if err != nil { - return err - } - } else { - bytesToWrite = protoutil.MarshalOrPanic(cds) - } - - logger.Debugf("Packaged chaincode into deployment spec of size %d, output file %s", len(bytesToWrite), p.Input.OutputFile) - err = os.WriteFile(p.Input.OutputFile, bytesToWrite, 0o700) - if err != nil { - logger.Errorf("failed writing deployment spec to file [%s]: [%s]", p.Input.OutputFile, err) - return err - } - - return err -} - -func getInstantiationPolicy(policy string) (*pcommon.SignaturePolicyEnvelope, error) { - p, err := policydsl.FromString(policy) - if err != nil { - return nil, errors.WithMessagef(err, "invalid policy %s", policy) - } - return p, nil -} - -// getChaincodeInstallPackage returns either a raw ChaincodeDeploymentSpec or -// a Envelope with ChaincodeDeploymentSpec and (optional) signature -func getChaincodeInstallPackage(cds *pb.ChaincodeDeploymentSpec, cf *ChaincodeCmdFactory) ([]byte, error) { - var owner identity.SignerSerializer - // check if we need to sign and set the owner - if createSignedCCDepSpec && signCCDepSpec { - if cf.Signer == nil { - return nil, errors.New("signing identity not found") - } - owner = cf.Signer - } - - ip := instantiationPolicy - if ip == "" { - // if an instantiation policy is not given, default - // to "admin must sign chaincode instantiation proposals" - mspid, err := mspmgmt.GetLocalMSP(factory.GetDefault()).GetIdentifier() - if err != nil { - return nil, err - } - ip = "AND('" + mspid + ".admin')" - } - - sp, err := getInstantiationPolicy(ip) - if err != nil { - return nil, err - } - - // we get the Envelope of type CHAINCODE_PACKAGE - objToWrite, err := ccpackage.OwnerCreateSignedCCDepSpec(cds, sp, owner) - if err != nil { - return nil, err - } - - // convert the proto object to bytes - bytesToWrite, err := proto.Marshal(objToWrite) - if err != nil { - return nil, errors.Wrap(err, "error marshalling chaincode package") - } - - return bytesToWrite, nil -} diff --git a/internal/peer/chaincode/package_test.go b/internal/peer/chaincode/package_test.go deleted file mode 100644 index 75da11a8bee..00000000000 --- a/internal/peer/chaincode/package_test.go +++ /dev/null @@ -1,213 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "os" - "testing" - - "github.com/golang/protobuf/proto" - pcommon "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/hyperledger/fabric/msp" - msptesttools "github.com/hyperledger/fabric/msp/mgmt/testtools" - "github.com/stretchr/testify/require" -) - -func TestMain(m *testing.M) { - err := msptesttools.LoadMSPSetupForTesting() - if err != nil { - panic(fmt.Sprintf("Fatal error when reading MSP config: %s", err)) - } - - os.Exit(m.Run()) -} - -func mockCDSFactory(spec *pb.ChaincodeSpec) (*pb.ChaincodeDeploymentSpec, error) { - return &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: []byte("somecode")}, nil -} - -func extractSignedCCDepSpec(env *pcommon.Envelope) (*pcommon.ChannelHeader, *pb.SignedChaincodeDeploymentSpec, error) { - p := &pcommon.Payload{} - err := proto.Unmarshal(env.Payload, p) - if err != nil { - return nil, nil, err - } - ch := &pcommon.ChannelHeader{} - err = proto.Unmarshal(p.Header.ChannelHeader, ch) - if err != nil { - return nil, nil, err - } - - sp := &pb.SignedChaincodeDeploymentSpec{} - err = proto.Unmarshal(p.Data, sp) - if err != nil { - return nil, nil, err - } - - return ch, sp, nil -} - -// TestCDSPackage tests generation of the old ChaincodeDeploymentSpec install -// which we will presumably continue to support at least for a bit -func TestCDSPackage(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", ccpackfile}, false) - if err != nil { - t.Fatalf("Run chaincode package cmd error:%v", err) - } - - b, err := os.ReadFile(ccpackfile) - if err != nil { - t.Fatalf("package file %s not created", ccpackfile) - } - cds := &pb.ChaincodeDeploymentSpec{} - err = proto.Unmarshal(b, cds) - if err != nil { - t.Fatalf("could not unmarshall package into CDS") - } -} - -// helper to create a SignedChaincodeDeploymentSpec -func createSignedCDSPackage(t *testing.T, args []string, sign bool) error { - p := newPackagerForTest(t, sign) - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - cmd := packageCmd(nil, mockCDSFactory, p, cryptoProvider) - addFlags(cmd) - - cmd.SetArgs(args) - - if err := cmd.Execute(); err != nil { - return err - } - - return nil -} - -func mockChaincodeCmdFactoryForTest(sign bool) (*ChaincodeCmdFactory, error) { - var signer msp.SigningIdentity - var err error - if sign { - signer, err = common.GetDefaultSigner() - if err != nil { - return nil, fmt.Errorf("Get default signer error: %v", err) - } - } - - cf := &ChaincodeCmdFactory{Signer: signer} - return cf, nil -} - -// TestSignedCDSPackage generates the new envelope encapsulating -// CDS, policy -func TestSignedCDSPackage(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", ccpackfile}, false) - if err != nil { - t.Fatalf("could not create signed cds package %s", err) - } - - b, err := os.ReadFile(ccpackfile) - if err != nil { - t.Fatalf("package file %s not created", ccpackfile) - } - - e := &pcommon.Envelope{} - err = proto.Unmarshal(b, e) - if err != nil { - t.Fatalf("could not unmarshall envelope") - } - - _, p, err := extractSignedCCDepSpec(e) - if err != nil { - t.Fatalf("could not extract signed dep spec") - } - - if p.OwnerEndorsements != nil { - t.Fatalf("expected no signatures but found endorsements") - } -} - -// TestSignedCDSPackageWithSignature generates the new envelope encapsulating -// CDS, policy and signs the package with local MSP -func TestSignedCDSPackageWithSignature(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", "-S", ccpackfile}, true) - if err != nil { - t.Fatalf("could not create signed cds package %s", err) - } - - b, err := os.ReadFile(ccpackfile) - if err != nil { - t.Fatalf("package file %s not created", ccpackfile) - } - e := &pcommon.Envelope{} - err = proto.Unmarshal(b, e) - if err != nil { - t.Fatalf("could not unmarshall envelope") - } - - _, p, err := extractSignedCCDepSpec(e) - if err != nil { - t.Fatalf("could not extract signed dep spec") - } - - if p.OwnerEndorsements == nil { - t.Fatalf("expected signatures and found nil") - } -} - -func TestNoOwnerToSign(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - // note "-S" requires signer but we are passing fase - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", "-S", ccpackfile}, false) - - if err == nil { - t.Fatalf("Expected error with nil signer but succeeded") - } -} - -func TestInvalidPolicy(t *testing.T) { - pdir := t.TempDir() - - ccpackfile := pdir + "/ccpack.file" - err := createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", "-i", "AND('a bad policy')", ccpackfile}, false) - - if err == nil { - t.Fatalf("Expected error with nil signer but succeeded") - } -} - -func newPackagerForTest(t *testing.T /*pr PlatformRegistry, w Writer,*/, sign bool) *Packager { - mockCF, err := mockChaincodeCmdFactoryForTest(sign) - if err != nil { - t.Fatal("error creating mock ChaincodeCmdFactory", err) - } - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - p := &Packager{ - ChaincodeCmdFactory: mockCF, - CDSFactory: mockCDSFactory, - CryptoProvider: cryptoProvider, - } - - return p -} diff --git a/internal/peer/chaincode/query.go b/internal/peer/chaincode/query.go deleted file mode 100644 index 83f9c65cd27..00000000000 --- a/internal/peer/chaincode/query.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "errors" - "fmt" - - "github.com/hyperledger/fabric/bccsp" - "github.com/spf13/cobra" -) - -var chaincodeQueryCmd *cobra.Command - -// queryCmd returns the cobra command for Chaincode Query -func queryCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeQueryCmd = &cobra.Command{ - Use: "query", - Short: fmt.Sprintf("Query using the specified %s.", chainFuncName), - Long: fmt.Sprintf("Get endorsed result of %s function call and print it. It won't generate transaction.", chainFuncName), - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - return chaincodeQuery(cmd, cf, cryptoProvider) - }, - } - flagList := []string{ - "ctor", - "name", - "channelID", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - } - attachFlags(chaincodeQueryCmd, flagList) - - chaincodeQueryCmd.Flags().BoolVarP(&chaincodeQueryRaw, "raw", "r", false, - "If true, output the query value as raw bytes, otherwise format as a printable string") - chaincodeQueryCmd.Flags().BoolVarP(&chaincodeQueryHex, "hex", "x", false, - "If true, output the query value byte array in hexadecimal. Incompatible with --raw") - - return chaincodeQueryCmd -} - -func chaincodeQuery(cmd *cobra.Command, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - if channelID == "" { - return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") - } - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, false, cryptoProvider) - if err != nil { - return err - } - } - - return chaincodeInvokeOrQuery(cmd, false, cf) -} diff --git a/internal/peer/chaincode/query_test.go b/internal/peer/chaincode/query_test.go deleted file mode 100644 index 9d15de866d3..00000000000 --- a/internal/peer/chaincode/query_test.go +++ /dev/null @@ -1,103 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "testing" - - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/spf13/cobra" - "github.com/stretchr/testify/require" -) - -func TestQueryCmd(t *testing.T) { - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err, "Error getting mock chaincode command factory") - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - // reset channelID, it might have been set by previous test - channelID = "" - - // Failure case: run query command without -C option - args := []string{"-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd := newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.Error(t, err, "'peer chaincode query' command should have failed without -C flag") - - // Success case: run query command without -r or -x option - args = []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd = newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.NoError(t, err, "Run chaincode query cmd error") - - // Success case: run query command with -r option - args = []string{"-r", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd = newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.NoError(t, err, "Run chaincode query cmd error") - chaincodeQueryRaw = false - - // Success case: run query command with -x option - args = []string{"-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd = newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.NoError(t, err, "Run chaincode query cmd error") - - // Failure case: run query command with both -x and -r options - args = []string{"-r", "-x", "-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd = newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.Error(t, err, "Expected error executing query command with both -r and -x options") - - // Failure case: run query command with mock chaincode cmd factory built to return error - mockCF, err = getMockChaincodeCmdFactoryWithErr() - require.NoError(t, err, "Error getting mock chaincode command factory") - args = []string{"-r", "-n", "example02", "-c", "{\"Args\": [\"query\",\"a\"]}"} - cmd = newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.Error(t, err, "Expected error executing query command") -} - -func TestQueryCmdEndorsementFailure(t *testing.T) { - args := []string{"-C", "mychannel", "-n", "example02", "-c", "{\"Args\": [\"queryinvalid\",\"a\"]}"} - ccRespStatus := [2]int32{502, 400} - ccRespPayload := [][]byte{[]byte("Invalid function name"), []byte("Incorrect parameters")} - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - for i := 0; i < 2; i++ { - mockCF, err := getMockChaincodeCmdFactoryEndorsementFailure(ccRespStatus[i], ccRespPayload[i]) - require.NoError(t, err, "Error getting mock chaincode command factory") - - cmd := newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.Error(t, err) - require.Regexp(t, "endorsement failure during query", err.Error()) - require.Regexp(t, fmt.Sprintf("response: status:%d payload:\"%s\"", ccRespStatus[i], ccRespPayload[i]), err.Error()) - } - - // failure - nil proposal response - mockCF, err := getMockChaincodeCmdFactory() - require.NoError(t, err, "Error getting mock chaincode command factory") - mockCF.EndorserClients[0] = common.GetMockEndorserClient(nil, nil) - mockCF.EndorserClients[1] = common.GetMockEndorserClient(nil, nil) - - cmd := newQueryCmdForTest(mockCF, args, cryptoProvider) - err = cmd.Execute() - require.Error(t, err) - require.Regexp(t, "error during query: received nil proposal response", err.Error()) -} - -func newQueryCmdForTest(cf *ChaincodeCmdFactory, args []string, cryptoProvider bccsp.BCCSP) *cobra.Command { - cmd := queryCmd(cf, cryptoProvider) - addFlags(cmd) - cmd.SetArgs(args) - return cmd -} diff --git a/internal/peer/chaincode/signpackage.go b/internal/peer/chaincode/signpackage.go deleted file mode 100644 index d99d2cff482..00000000000 --- a/internal/peer/chaincode/signpackage.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "os" - - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/core/common/ccpackage" - "github.com/hyperledger/fabric/protoutil" - "github.com/spf13/cobra" -) - -// signpackageCmd returns the cobra command for signing a package -func signpackageCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - spCmd := &cobra.Command{ - Use: "signpackage", - Short: "Sign the specified chaincode package", - Long: "Sign the specified chaincode package", - ValidArgs: []string{"2"}, - RunE: func(cmd *cobra.Command, args []string) error { - if len(args) < 2 { - return fmt.Errorf("peer chaincode signpackage ") - } - return signpackage(cmd, args[0], args[1], cf, cryptoProvider) - }, - } - - return spCmd -} - -func signpackage(cmd *cobra.Command, ipackageFile string, opackageFile string, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), false, false, cryptoProvider) - if err != nil { - return err - } - } - - b, err := os.ReadFile(ipackageFile) - if err != nil { - return err - } - - env := protoutil.UnmarshalEnvelopeOrPanic(b) - - env, err = ccpackage.SignExistingPackage(env, cf.Signer) - if err != nil { - return err - } - - b = protoutil.MarshalOrPanic(env) - err = os.WriteFile(opackageFile, b, 0o700) - if err != nil { - return err - } - - fmt.Printf("Wrote signed package to %s successfully\n", opackageFile) - - return nil -} diff --git a/internal/peer/chaincode/signpackage_test.go b/internal/peer/chaincode/signpackage_test.go deleted file mode 100644 index dd2de3370df..00000000000 --- a/internal/peer/chaincode/signpackage_test.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "fmt" - "os" - "testing" - - "github.com/golang/protobuf/proto" - pcommon "github.com/hyperledger/fabric-protos-go/common" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/stretchr/testify/require" -) - -// helper to sign an existing package -func signExistingPackage(env *pcommon.Envelope, infile, outfile string, cryptoProvider bccsp.BCCSP) error { - signer, err := common.GetDefaultSigner() - if err != nil { - return fmt.Errorf("Get default signer error: %v", err) - } - - mockCF := &ChaincodeCmdFactory{Signer: signer} - - cmd := signpackageCmd(mockCF, cryptoProvider) - addFlags(cmd) - - cmd.SetArgs([]string{infile, outfile}) - - if err := cmd.Execute(); err != nil { - return err - } - - return nil -} - -// TestSignExistingPackage signs an existing package -func TestSignExistingPackage(t *testing.T) { - resetFlags() - defer resetFlags() - pdir := t.TempDir() - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - ccpackfile := pdir + "/ccpack.file" - err = createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", "-S", ccpackfile}, true) - if err != nil { - t.Fatalf("error creating signed :%v", err) - } - - b, err := os.ReadFile(ccpackfile) - if err != nil { - t.Fatalf("package file %s not created", ccpackfile) - } - - e := &pcommon.Envelope{} - err = proto.Unmarshal(b, e) - if err != nil { - t.Fatalf("could not unmarshall envelope") - } - - signedfile := pdir + "/signed.file" - err = signExistingPackage(e, ccpackfile, signedfile, cryptoProvider) - if err != nil { - t.Fatalf("could not sign envelope") - } - - b, err = os.ReadFile(signedfile) - if err != nil { - t.Fatalf("signed package file %s not created", signedfile) - } - - e = &pcommon.Envelope{} - err = proto.Unmarshal(b, e) - if err != nil { - t.Fatalf("could not unmarshall signed envelope") - } - - _, p, err := extractSignedCCDepSpec(e) - if err != nil { - t.Fatalf("could not extract signed dep spec") - } - - if p.OwnerEndorsements == nil { - t.Fatalf("expected endorsements") - } - - if len(p.OwnerEndorsements) != 2 { - t.Fatalf("expected 2 endorserments but found %d", len(p.OwnerEndorsements)) - } -} - -// TestFailSignUnsignedPackage tries to signs a package that was not originally signed -func TestFailSignUnsignedPackage(t *testing.T) { - resetFlags() - defer resetFlags() - pdir := t.TempDir() - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - - ccpackfile := pdir + "/ccpack.file" - // don't sign it ... no "-S" - err = createSignedCDSPackage(t, []string{"-n", "somecc", "-p", "some/go/package", "-v", "0", "-s", ccpackfile}, true) - if err != nil { - t.Fatalf("error creating signed :%v", err) - } - - b, err := os.ReadFile(ccpackfile) - if err != nil { - t.Fatalf("package file %s not created", ccpackfile) - } - - e := &pcommon.Envelope{} - err = proto.Unmarshal(b, e) - if err != nil { - t.Fatalf("could not unmarshall envelope") - } - - signedfile := pdir + "/signed.file" - err = signExistingPackage(e, ccpackfile, signedfile, cryptoProvider) - if err == nil { - t.Fatalf("expected signing a package that's not originally signed to fail") - } -} diff --git a/internal/peer/chaincode/testdata/connectionprofile-uneven.yaml b/internal/peer/chaincode/testdata/connectionprofile-uneven.yaml deleted file mode 100644 index e95e23d7926..00000000000 --- a/internal/peer/chaincode/testdata/connectionprofile-uneven.yaml +++ /dev/null @@ -1,184 +0,0 @@ -name: connection-profile-uneven-peers - -# -# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming -# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave -# them for the applications to process. This is a mechanism for different components of an application -# to exchange information that are not part of the standard schema described below. In particular, -# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to -# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. -# -x-type: "hlfv1" -x-loggingLevel: info - -# -# Describe what the target network is/does. -# -description: "The network to be in if you want to stay in the global trade business" - -# -# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. -# -version: 1.2.0 - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mychannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org1" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - orderers: - - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org1.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - peer0.org2.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - -# -# list of participating organizations in this network -# -organizations: - org1: - mspid: Org1MSP - - # This org's MSP store (absolute path or relative to client.cryptoconfig) - cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp - - peers: - - peer0.org1.example.com - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - org2: - mspid: Org2MSP - - # This org's MSP store (absolute path or relative to client.cryptoconfig) - cryptoPath: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp - - peers: - - peer0.org2.example.com - - # Orderer Org name - ordererorg: - # Membership Service Provider ID for this organization - mspID: "OrdererOrg" - - # Needed to load users crypto keys and certs for this org (absolute path or relative to global crypto path, DEV mode) - cryptoPath: ordererOrganizations/example.com/users/Admin@example.com/msp - - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - local.orderer.example.com: - url: orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - # These parameters should be set in coordination with the keepalive policy on the server, - # as incompatible settings can result in closing of connection. - # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org1.example.com: - # this URL is used to send endorsement and query requests - url: peer0.org1.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org1.example.com - # These parameters should be set in coordination with the keepalive policy on the server, - # as incompatible settings can result in closing of connection. - # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem - - # peer0.org2.example.com: - # url: peer0.org2.example.com:7051 - # grpcOptions: - # ssl-target-name-override: peer0.org2.example.com - # # These parameters should be set in coordination with the keepalive policy on the server, - # # as incompatible settings can result in closing of connection. - # # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - # keep-alive-time: 0s - # keep-alive-timeout: 20s - # keep-alive-permit: false - # fail-fast: false - # # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - # allow-insecure: false - - # tlsCACerts: - # path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem diff --git a/internal/peer/chaincode/testdata/connectionprofile.yaml b/internal/peer/chaincode/testdata/connectionprofile.yaml deleted file mode 100644 index 5ae74e952f8..00000000000 --- a/internal/peer/chaincode/testdata/connectionprofile.yaml +++ /dev/null @@ -1,184 +0,0 @@ -name: connection-profile - -# -# Any properties with an "x-" prefix will be treated as application-specific, exactly like how naming -# in HTTP headers or swagger properties work. The SDK will simply ignore these fields and leave -# them for the applications to process. This is a mechanism for different components of an application -# to exchange information that are not part of the standard schema described below. In particular, -# the "x-type" property with the "hlfv1" value example below is used by Hyperledger Composer to -# determine the type of Fabric networks (v0.6 vs. v1.0) it needs to work with. -# -x-type: "hlfv1" -x-loggingLevel: info - -# -# Describe what the target network is/does. -# -description: "The network to be in if you want to stay in the global trade business" - -# -# Schema version of the content. Used by the SDK to apply the corresponding parsing rules. -# -version: 1.2.0 - -# -# [Optional]. But most apps would have this section so that channel objects can be constructed -# based on the content below. If an app is creating channels, then it likely will not need this -# section. -# -channels: - # name of the channel - mychannel: - # Required. list of orderers designated by the application to use for transactions on this - # channel. This list can be a result of access control ("org1" can only access "ordererA"), or - # operational decisions to share loads from applications among the orderers. The values must - # be "names" of orgs defined under "organizations/peers" - orderers: - - orderer.example.com - - # Required. list of peers from participating orgs - peers: - peer0.org1.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - - peer0.org2.example.com: - # [Optional]. will this peer be sent transaction proposals for endorsement? The peer must - # have the chaincode installed. The app can also use this property to decide which peers - # to send the chaincode install request. Default: true - endorsingPeer: true - - # [Optional]. will this peer be sent query proposals? The peer must have the chaincode - # installed. The app can also use this property to decide which peers to send the - # chaincode install request. Default: true - chaincodeQuery: true - - # [Optional]. will this peer be sent query proposals that do not require chaincodes, like - # queryBlock(), queryTransaction(), etc. Default: true - ledgerQuery: true - - # [Optional]. will this peer be the target of the SDK's listener registration? All peers can - # produce events but the app typically only needs to connect to one to listen to events. - # Default: true - eventSource: true - -# -# list of participating organizations in this network -# -organizations: - org1: - mspid: Org1MSP - - # This org's MSP store (absolute path or relative to client.cryptoconfig) - cryptoPath: peerOrganizations/org1.example.com/users/{username}@org1.example.com/msp - - peers: - - peer0.org1.example.com - - # the profile will contain public information about organizations other than the one it belongs to. - # These are necessary information to make transaction lifecycles work, including MSP IDs and - # peers with a public URL to send transaction proposals. The file will not contain private - # information reserved for members of the organization, such as admin key and certificate, - # fabric-ca registrar enroll ID and secret, etc. - org2: - mspid: Org2MSP - - # This org's MSP store (absolute path or relative to client.cryptoconfig) - cryptoPath: peerOrganizations/org2.example.com/users/{username}@org2.example.com/msp - - peers: - - peer0.org2.example.com - - # Orderer Org name - ordererorg: - # Membership Service Provider ID for this organization - mspID: "OrdererOrg" - - # Needed to load users crypto keys and certs for this org (absolute path or relative to global crypto path, DEV mode) - cryptoPath: ordererOrganizations/example.com/users/{username}@example.com/msp - - -# -# List of orderers to send transaction and channel create/update requests to. For the time -# being only one orderer is needed. If more than one is defined, which one get used by the -# SDK is implementation specific. Consult each SDK's documentation for its handling of orderers. -# -orderers: - local.orderer.example.com: - url: orderer.example.com:7050 - - # these are standard properties defined by the gRPC library - # they will be passed in as-is to gRPC client constructor - grpcOptions: - ssl-target-name-override: orderer.example.com - # These parameters should be set in coordination with the keepalive policy on the server, - # as incompatible settings can result in closing of connection. - # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/tlsca/tlsca.example.com-cert.pem - -# -# List of peers to send various requests to, including endorsement, query -# and event listener registration. -# -peers: - peer0.org1.example.com: - # this URL is used to send endorsement and query requests - url: peer0.org1.example.com:7051 - - grpcOptions: - ssl-target-name-override: peer0.org1.example.com - # These parameters should be set in coordination with the keepalive policy on the server, - # as incompatible settings can result in closing of connection. - # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - # Certificate location absolute path - path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/tlsca/tlsca.org1.example.com-cert.pem - - peer0.org2.example.com: - url: peer0.org2.example.com:7051 - grpcOptions: - ssl-target-name-override: peer0.org2.example.com - # These parameters should be set in coordination with the keepalive policy on the server, - # as incompatible settings can result in closing of connection. - # When duration of the 'keep-alive-time' is set to 0 or less the keep alive client parameters are disabled - keep-alive-time: 0s - keep-alive-timeout: 20s - keep-alive-permit: false - fail-fast: false - # allow-insecure will be taken into consideration if address has no protocol defined, if true then grpc or else grpcs - allow-insecure: false - - tlsCACerts: - path: /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/tlsca/tlsca.org2.example.com-cert.pem diff --git a/internal/peer/chaincode/testdata/src/chaincodes/noop/chaincode.go b/internal/peer/chaincode/testdata/src/chaincodes/noop/chaincode.go deleted file mode 100644 index 71058bd41fa..00000000000 --- a/internal/peer/chaincode/testdata/src/chaincodes/noop/chaincode.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package main - -import ( - "fmt" - - "github.com/hyperledger/fabric-chaincode-go/shim" - pb "github.com/hyperledger/fabric-protos-go/peer" -) - -// No-op test chaincode -type TestChaincode struct{} - -func (t *TestChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { - return shim.Success(nil) -} - -func (t *TestChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { - return shim.Success(nil) -} - -func main() { - err := shim.Start(new(TestChaincode)) - if err != nil { - fmt.Printf("Error starting Simple chaincode: %s", err) - } -} diff --git a/internal/peer/chaincode/upgrade.go b/internal/peer/chaincode/upgrade.go deleted file mode 100644 index 04f99951f83..00000000000 --- a/internal/peer/chaincode/upgrade.go +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "context" - "errors" - "fmt" - - protcommon "github.com/hyperledger/fabric-protos-go/common" - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/protoutil" - "github.com/spf13/cobra" -) - -var chaincodeUpgradeCmd *cobra.Command - -const upgradeCmdName = "upgrade" - -// upgradeCmd returns the cobra command for Chaincode Upgrade -func upgradeCmd(cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) *cobra.Command { - chaincodeUpgradeCmd = &cobra.Command{ - Use: upgradeCmdName, - Short: "Upgrade chaincode.", - Long: "Upgrade an existing chaincode with the specified one. The new chaincode will immediately replace the existing chaincode upon the transaction committed.", - ValidArgs: []string{"1"}, - RunE: func(cmd *cobra.Command, args []string) error { - return chaincodeUpgrade(cmd, args, cf, cryptoProvider) - }, - } - flagList := []string{ - "lang", - "ctor", - "path", - "name", - "channelID", - "version", - "policy", - "escc", - "vscc", - "peerAddresses", - "tlsRootCertFiles", - "connectionProfile", - "collections-config", - } - attachFlags(chaincodeUpgradeCmd, flagList) - - return chaincodeUpgradeCmd -} - -// upgrade the command via Endorser -func upgrade(cmd *cobra.Command, cf *ChaincodeCmdFactory) (*protcommon.Envelope, error) { - spec, err := getChaincodeSpec(cmd) - if err != nil { - return nil, err - } - - cds, err := getChaincodeDeploymentSpec(spec, false) - if err != nil { - return nil, fmt.Errorf("error getting chaincode code %s: %s", chaincodeName, err) - } - - creator, err := cf.Signer.Serialize() - if err != nil { - return nil, fmt.Errorf("error serializing identity: %s", err) - } - - prop, _, err := protoutil.CreateUpgradeProposalFromCDS(channelID, cds, creator, policyMarshalled, []byte(escc), []byte(vscc), collectionConfigBytes) - if err != nil { - return nil, fmt.Errorf("error creating proposal %s: %s", chainFuncName, err) - } - logger.Debugf("Get upgrade proposal for chaincode <%v>", spec.ChaincodeId) - - var signedProp *pb.SignedProposal - signedProp, err = protoutil.GetSignedProposal(prop, cf.Signer) - if err != nil { - return nil, fmt.Errorf("error creating signed proposal %s: %s", chainFuncName, err) - } - - // upgrade is currently only supported for one peer - proposalResponse, err := cf.EndorserClients[0].ProcessProposal(context.Background(), signedProp) - if err != nil { - return nil, fmt.Errorf("error endorsing %s: %s", chainFuncName, err) - } - - if proposalResponse != nil { - logger.Debugf("endorse upgrade proposal, get response <%v>", proposalResponse.Response) - // assemble a signed transaction (it's an Envelope message) - env, err := protoutil.CreateSignedTx(prop, cf.Signer, proposalResponse) - if err != nil { - return nil, fmt.Errorf("could not assemble transaction, err %s", err) - } - logger.Debug("Get Signed envelope") - return env, nil - } - - return nil, nil -} - -// chaincodeUpgrade upgrades the chaincode. On success, the new chaincode -// version is printed to STDOUT -func chaincodeUpgrade(cmd *cobra.Command, args []string, cf *ChaincodeCmdFactory, cryptoProvider bccsp.BCCSP) error { - if channelID == "" { - return errors.New("The required parameter 'channelID' is empty. Rerun the command with -C flag") - } - // Parsing of the command line is done so silence cmd usage - cmd.SilenceUsage = true - - var err error - if cf == nil { - cf, err = InitCmdFactory(cmd.Name(), true, true, cryptoProvider) - if err != nil { - return err - } - } - defer cf.BroadcastClient.Close() - - env, err := upgrade(cmd, cf) - if err != nil { - return err - } - - if env != nil { - logger.Debug("Send signed envelope to orderer") - err = cf.BroadcastClient.Send(env) - return err - } - - return nil -} diff --git a/internal/peer/chaincode/upgrade_test.go b/internal/peer/chaincode/upgrade_test.go deleted file mode 100644 index bedc0855a9a..00000000000 --- a/internal/peer/chaincode/upgrade_test.go +++ /dev/null @@ -1,171 +0,0 @@ -/* -Copyright Digital Asset Holdings, LLC. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package chaincode - -import ( - "errors" - "fmt" - "testing" - "time" - - pb "github.com/hyperledger/fabric-protos-go/peer" - "github.com/hyperledger/fabric/bccsp/sw" - "github.com/hyperledger/fabric/internal/peer/common" - "github.com/spf13/viper" - "github.com/stretchr/testify/require" -) - -func TestUpgradeCmd(t *testing.T) { - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %v", err) - } - - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 200}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - } - - // reset channelID, it might have been set by previous test - channelID = "" - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - cmd := upgradeCmd(mockCF, cryptoProvider) - addFlags(cmd) - - args := []string{ - "-n", "mychaincode", "-p", "mychaincodepath", - "-v", "anotherversion", "-c", "{\"Function\":\"init\",\"Args\": [\"param\",\"1\"]}", - } - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "'peer chaincode upgrade' command should have failed without -C flag") - - args = []string{ - "-C", "mychannel", "-n", "mychaincode", "-p", "mychaincodepath", - "-v", "anotherversion", "-c", "{\"Function\":\"init\",\"Args\": [\"param\",\"1\"]}", - } - cmd.SetArgs(args) - err = cmd.Execute() - require.NoError(t, err, "'peer chaincode upgrade' command failed") -} - -func TestUpgradeCmdEndorseFail(t *testing.T) { - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %v", err) - } - - errCode := int32(500) - errMsg := "upgrade error" - mockResponse := &pb.ProposalResponse{Response: &pb.Response{Status: errCode, Message: errMsg}} - - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil)} - mockBroadcastClient := common.GetMockBroadcastClient(nil) - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - } - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - cmd := upgradeCmd(mockCF, cryptoProvider) - addFlags(cmd) - - args := []string{ - "-C", "mychannel", "-n", "mychaincode", "-p", "mychaincodepath", - "-v", "anotherversion", "-c", "{\"Function\":\"init\",\"Args\": [\"param\",\"1\"]}", - } - cmd.SetArgs(args) - - expectErrMsg := fmt.Sprintf("could not assemble transaction, err proposal response was not successful, error code %d, msg %s", errCode, errMsg) - if err := cmd.Execute(); err == nil { - t.Errorf("Run chaincode upgrade cmd error:%v", err) - } else { - if err.Error() != expectErrMsg { - t.Errorf("Run chaincode upgrade cmd get unexpected error: %s", err.Error()) - } - } -} - -func TestUpgradeCmdSendTXFail(t *testing.T) { - signer, err := common.GetDefaultSigner() - if err != nil { - t.Fatalf("Get default signer error: %v", err) - } - - mockResponse := &pb.ProposalResponse{ - Response: &pb.Response{Status: 200}, - Endorsement: &pb.Endorsement{}, - } - mockEndorserClients := []pb.EndorserClient{common.GetMockEndorserClient(mockResponse, nil)} - sendErr := errors.New("send tx failed") - mockBroadcastClient := common.GetMockBroadcastClient(sendErr) - mockCF := &ChaincodeCmdFactory{ - EndorserClients: mockEndorserClients, - Signer: signer, - BroadcastClient: mockBroadcastClient, - } - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - cmd := upgradeCmd(mockCF, cryptoProvider) - addFlags(cmd) - - args := []string{"-C", "mychannel", "-n", "mychaincode", "-p", "mychaincodepath", "-v", "anotherversion", "-c", "{\"Function\":\"init\",\"Args\": [\"param\",\"1\"]}"} - cmd.SetArgs(args) - - expectErrMsg := sendErr.Error() - if err := cmd.Execute(); err == nil { - t.Errorf("Run chaincode upgrade cmd error:%v", err) - } else { - if err.Error() != expectErrMsg { - t.Errorf("Run chaincode upgrade cmd get unexpected error: %s", err.Error()) - } - } -} - -func TestUpgradeCmdWithNilCF(t *testing.T) { - defer viper.Reset() - defer resetFlags() - - // set timeout for failure cases - viper.Set("peer.client.connTimeout", 10*time.Millisecond) - - // trap possible SIGSEV panic - defer func() { - var err error - if r := recover(); r != nil { - err = fmt.Errorf("%v", r) - } - require.NoError(t, err, "'peer chaincode upgrade' command should have failed without a panic") - }() - - channelID = "" - - cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) - require.NoError(t, err) - cmd := upgradeCmd(nil, cryptoProvider) - addFlags(cmd) - - args := []string{ - "-C", "mychannel", "-n", "mychaincode", "-p", "mychaincodepath", - "-v", "anotherversion", "-c", "{\"Function\":\"init\",\"Args\": [\"param\",\"1\"]}", - } - cmd.SetArgs(args) - err = cmd.Execute() - require.Error(t, err, "'peer chaincode upgrade' command should have failed without a panic") -} diff --git a/internal/peer/lifecycle/chaincode/approveformyorg.go b/internal/peer/lifecycle/chaincode/approveformyorg.go index db312019e7f..290511dee36 100644 --- a/internal/peer/lifecycle/chaincode/approveformyorg.go +++ b/internal/peer/lifecycle/chaincode/approveformyorg.go @@ -16,7 +16,6 @@ import ( pb "github.com/hyperledger/fabric-protos-go/peer" lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/internal/peer/chaincode" "github.com/hyperledger/fabric/internal/peer/common" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" @@ -206,14 +205,14 @@ func (a *ApproverForMyOrg) Approve() error { if err != nil { return errors.WithMessage(err, "failed to create signed transaction") } - var dg *chaincode.DeliverGroup + var dg *DeliverGroup var ctx context.Context if a.Input.WaitForEvent { var cancelFunc context.CancelFunc ctx, cancelFunc = context.WithTimeout(context.Background(), a.Input.WaitForEventTimeout) defer cancelFunc() - dg = chaincode.NewDeliverGroup( + dg = NewDeliverGroup( a.DeliverClients, a.Input.PeerAddresses, a.Signer, diff --git a/internal/peer/lifecycle/chaincode/commit.go b/internal/peer/lifecycle/chaincode/commit.go index bc0be67a8af..61f381a4e75 100644 --- a/internal/peer/lifecycle/chaincode/commit.go +++ b/internal/peer/lifecycle/chaincode/commit.go @@ -16,7 +16,6 @@ import ( pb "github.com/hyperledger/fabric-protos-go/peer" lb "github.com/hyperledger/fabric-protos-go/peer/lifecycle" "github.com/hyperledger/fabric/bccsp" - "github.com/hyperledger/fabric/internal/peer/chaincode" "github.com/hyperledger/fabric/internal/peer/common" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" @@ -205,14 +204,14 @@ func (c *Committer) Commit() error { return errors.WithMessage(err, "failed to create signed transaction") } - var dg *chaincode.DeliverGroup + var dg *DeliverGroup var ctx context.Context if c.Input.WaitForEvent { var cancelFunc context.CancelFunc ctx, cancelFunc = context.WithTimeout(context.Background(), c.Input.WaitForEventTimeout) defer cancelFunc() - dg = chaincode.NewDeliverGroup( + dg = NewDeliverGroup( c.DeliverClients, c.Input.PeerAddresses, c.Signer, diff --git a/internal/peer/lifecycle/chaincode/common.go b/internal/peer/lifecycle/chaincode/common.go index 1773e5bf104..369da56017a 100644 --- a/internal/peer/lifecycle/chaincode/common.go +++ b/internal/peer/lifecycle/chaincode/common.go @@ -8,19 +8,260 @@ package chaincode import ( "context" + "crypto/tls" "encoding/json" "fmt" "io" + "math" + "os" + "sync" "github.com/golang/protobuf/proto" + pcommon "github.com/hyperledger/fabric-protos-go/common" + ab "github.com/hyperledger/fabric-protos-go/orderer" pb "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric/common/policydsl" - "github.com/hyperledger/fabric/internal/peer/chaincode" + "github.com/hyperledger/fabric/common/util" + "github.com/hyperledger/fabric/internal/pkg/identity" "github.com/hyperledger/fabric/protoutil" "github.com/pkg/errors" + "github.com/spf13/viper" "google.golang.org/grpc" ) +// DeliverGroup holds all of the information needed to connect +// to a set of peers to wait for the interested txid to be +// committed to the ledgers of all peers. This functionality +// is currently implemented via the peer's DeliverFiltered service. +// An error from any of the peers/deliver clients will result in +// the invoke command returning an error. Only the first error that +// occurs will be set +type DeliverGroup struct { + Clients []*DeliverClient + Certificate tls.Certificate + ChannelID string + TxID string + Signer identity.SignerSerializer + mutex sync.Mutex + Error error + wg sync.WaitGroup +} + +// DeliverClient holds the client/connection related to a specific +// peer. The address is included for logging purposes +type DeliverClient struct { + Client pb.DeliverClient + Connection pb.Deliver_DeliverClient + Address string +} + +func NewDeliverGroup( + deliverClients []pb.DeliverClient, + peerAddresses []string, + signer identity.SignerSerializer, + certificate tls.Certificate, + channelID string, + txid string, +) *DeliverGroup { + clients := make([]*DeliverClient, len(deliverClients)) + for i, client := range deliverClients { + address := peerAddresses[i] + if address == "" { + address = viper.GetString("peer.address") + } + dc := &DeliverClient{ + Client: client, + Address: address, + } + clients[i] = dc + } + + dg := &DeliverGroup{ + Clients: clients, + Certificate: certificate, + ChannelID: channelID, + TxID: txid, + Signer: signer, + } + + return dg +} + +// Connect waits for all deliver clients in the group to connect to +// the peer's deliver service, receive an error, or for the context +// to timeout. An error will be returned whenever even a single +// deliver client fails to connect to its peer +func (dg *DeliverGroup) Connect(ctx context.Context) error { + dg.wg.Add(len(dg.Clients)) + for _, client := range dg.Clients { + go dg.ClientConnect(ctx, client) + } + readyCh := make(chan struct{}) + go dg.WaitForWG(readyCh) + + select { + case <-readyCh: + if dg.Error != nil { + err := errors.WithMessage(dg.Error, "failed to connect to deliver on all peers") + return err + } + case <-ctx.Done(): + err := errors.New("timed out waiting for connection to deliver on all peers") + return err + } + + return nil +} + +// ClientConnect sends a deliver seek info envelope using the +// provided deliver client, setting the deliverGroup's Error +// field upon any error +func (dg *DeliverGroup) ClientConnect(ctx context.Context, dc *DeliverClient) { + defer dg.wg.Done() + df, err := dc.Client.DeliverFiltered(ctx) + if err != nil { + err = errors.WithMessagef(err, "error connecting to deliver filtered at %s", dc.Address) + dg.setError(err) + return + } + defer df.CloseSend() + dc.Connection = df + + envelope := createDeliverEnvelope(dg.ChannelID, dg.Certificate, dg.Signer) + err = df.Send(envelope) + if err != nil { + err = errors.WithMessagef(err, "error sending deliver seek info envelope to %s", dc.Address) + dg.setError(err) + return + } +} + +// Wait waits for all deliver client connections in the group to +// either receive a block with the txid, an error, or for the +// context to timeout +func (dg *DeliverGroup) Wait(ctx context.Context) error { + if len(dg.Clients) == 0 { + return nil + } + + dg.wg.Add(len(dg.Clients)) + for _, client := range dg.Clients { + go dg.ClientWait(client) + } + readyCh := make(chan struct{}) + go dg.WaitForWG(readyCh) + + select { + case <-readyCh: + if dg.Error != nil { + return dg.Error + } + case <-ctx.Done(): + err := errors.New("timed out waiting for txid on all peers") + return err + } + + return nil +} + +// ClientWait waits for the specified deliver client to receive +// a block event with the requested txid +func (dg *DeliverGroup) ClientWait(dc *DeliverClient) { + defer dg.wg.Done() + for { + resp, err := dc.Connection.Recv() + if err != nil { + err = errors.WithMessagef(err, "error receiving from deliver filtered at %s", dc.Address) + dg.setError(err) + return + } + switch r := resp.Type.(type) { + case *pb.DeliverResponse_FilteredBlock: + filteredTransactions := r.FilteredBlock.FilteredTransactions + for _, tx := range filteredTransactions { + if tx.Txid == dg.TxID { + logger.Infof("txid [%s] committed with status (%s) at %s", dg.TxID, tx.TxValidationCode, dc.Address) + if tx.TxValidationCode != pb.TxValidationCode_VALID { + err = errors.Errorf("transaction invalidated with status (%s)", tx.TxValidationCode) + dg.setError(err) + } + return + } + } + case *pb.DeliverResponse_Status: + err = errors.Errorf("deliver completed with status (%s) before txid received", r.Status) + dg.setError(err) + return + default: + err = errors.Errorf("received unexpected response type (%T) from %s", r, dc.Address) + dg.setError(err) + return + } + } +} + +// WaitForWG waits for the deliverGroup's wait group and closes +// the channel when ready +func (dg *DeliverGroup) WaitForWG(readyCh chan struct{}) { + dg.wg.Wait() + close(readyCh) +} + +// setError serializes an error for the deliverGroup +func (dg *DeliverGroup) setError(err error) { + dg.mutex.Lock() + dg.Error = err + dg.mutex.Unlock() +} + +func createDeliverEnvelope( + channelID string, + certificate tls.Certificate, + signer identity.SignerSerializer, +) *pcommon.Envelope { + var tlsCertHash []byte + // check for client certificate and create hash if present + if len(certificate.Certificate) > 0 { + tlsCertHash = util.ComputeSHA256(certificate.Certificate[0]) + } + + start := &ab.SeekPosition{ + Type: &ab.SeekPosition_Newest{ + Newest: &ab.SeekNewest{}, + }, + } + + stop := &ab.SeekPosition{ + Type: &ab.SeekPosition_Specified{ + Specified: &ab.SeekSpecified{ + Number: math.MaxUint64, + }, + }, + } + + seekInfo := &ab.SeekInfo{ + Start: start, + Stop: stop, + Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, + } + + env, err := protoutil.CreateSignedEnvelopeWithTLSBinding( + pcommon.HeaderType_DELIVER_SEEK_INFO, + channelID, + signer, + seekInfo, + int32(0), + uint64(0), + tlsCertHash, + ) + if err != nil { + logger.Errorf("Error signing envelope: %s", err) + return nil + } + + return env +} + // EndorserClient defines the interface for sending a proposal // to an endorser type EndorserClient interface { @@ -111,7 +352,7 @@ func createCollectionConfigPackage(collectionsConfigFile string) (*pb.Collection var ccp *pb.CollectionConfigPackage if collectionsConfigFile != "" { var err error - ccp, _, err = chaincode.GetCollectionConfigFromFile(collectionsConfigFile) + ccp, _, err = GetCollectionConfigFromFile(collectionsConfigFile) if err != nil { return nil, errors.WithMessagef(err, "invalid collection configuration in file %s", collectionsConfigFile) } @@ -119,6 +360,136 @@ func createCollectionConfigPackage(collectionsConfigFile string) (*pb.Collection return ccp, nil } +type endorsementPolicy struct { + ChannelConfigPolicy string `json:"channelConfigPolicy,omitempty"` + SignaturePolicy string `json:"signaturePolicy,omitempty"` +} + +type collectionConfigJson struct { + Name string `json:"name"` + Policy string `json:"policy"` + RequiredPeerCount *int32 `json:"requiredPeerCount"` + MaxPeerCount *int32 `json:"maxPeerCount"` + BlockToLive uint64 `json:"blockToLive"` + MemberOnlyRead bool `json:"memberOnlyRead"` + MemberOnlyWrite bool `json:"memberOnlyWrite"` + EndorsementPolicy *endorsementPolicy `json:"endorsementPolicy,omitempty"` +} + +// GetCollectionConfigFromFile retrieves the collection configuration +// from the supplied file; the supplied file must contain a +// json-formatted array of collectionConfigJson elements +func GetCollectionConfigFromFile(ccFile string) (*pb.CollectionConfigPackage, []byte, error) { + fileBytes, err := os.ReadFile(ccFile) + if err != nil { + return nil, nil, errors.Wrapf(err, "could not read file '%s'", ccFile) + } + + return getCollectionConfigFromBytes(fileBytes) +} + +// getCollectionConfig retrieves the collection configuration +// from the supplied byte array; the byte array must contain a +// json-formatted array of collectionConfigJson elements +func getCollectionConfigFromBytes(cconfBytes []byte) (*pb.CollectionConfigPackage, []byte, error) { + cconf := &[]collectionConfigJson{} + err := json.Unmarshal(cconfBytes, cconf) + if err != nil { + return nil, nil, errors.Wrap(err, "could not parse the collection configuration") + } + + ccarray := make([]*pb.CollectionConfig, 0, len(*cconf)) + for _, cconfitem := range *cconf { + p, err := policydsl.FromString(cconfitem.Policy) + if err != nil { + return nil, nil, errors.WithMessagef(err, "invalid policy %s", cconfitem.Policy) + } + + cpc := &pb.CollectionPolicyConfig{ + Payload: &pb.CollectionPolicyConfig_SignaturePolicy{ + SignaturePolicy: p, + }, + } + + var ep *pb.ApplicationPolicy + if cconfitem.EndorsementPolicy != nil { + signaturePolicy := cconfitem.EndorsementPolicy.SignaturePolicy + channelConfigPolicy := cconfitem.EndorsementPolicy.ChannelConfigPolicy + ep, err = getApplicationPolicy(signaturePolicy, channelConfigPolicy) + if err != nil { + return nil, nil, errors.WithMessagef(err, "invalid endorsement policy [%#v]", cconfitem.EndorsementPolicy) + } + } + + // Set default requiredPeerCount and MaxPeerCount if not specified in json + requiredPeerCount := int32(0) + maxPeerCount := int32(1) + if cconfitem.RequiredPeerCount != nil { + requiredPeerCount = *cconfitem.RequiredPeerCount + } + if cconfitem.MaxPeerCount != nil { + maxPeerCount = *cconfitem.MaxPeerCount + } + + cc := &pb.CollectionConfig{ + Payload: &pb.CollectionConfig_StaticCollectionConfig{ + StaticCollectionConfig: &pb.StaticCollectionConfig{ + Name: cconfitem.Name, + MemberOrgsPolicy: cpc, + RequiredPeerCount: requiredPeerCount, + MaximumPeerCount: maxPeerCount, + BlockToLive: cconfitem.BlockToLive, + MemberOnlyRead: cconfitem.MemberOnlyRead, + MemberOnlyWrite: cconfitem.MemberOnlyWrite, + EndorsementPolicy: ep, + }, + }, + } + + ccarray = append(ccarray, cc) + } + + ccp := &pb.CollectionConfigPackage{Config: ccarray} + ccpBytes, err := proto.Marshal(ccp) + return ccp, ccpBytes, err +} + +func getApplicationPolicy(signaturePolicy, channelConfigPolicy string) (*pb.ApplicationPolicy, error) { + if signaturePolicy == "" && channelConfigPolicy == "" { + // no policy, no problem + return nil, nil + } + + if signaturePolicy != "" && channelConfigPolicy != "" { + // mo policies, mo problems + return nil, errors.New(`cannot specify both "--signature-policy" and "--channel-config-policy"`) + } + + var applicationPolicy *pb.ApplicationPolicy + if signaturePolicy != "" { + signaturePolicyEnvelope, err := policydsl.FromString(signaturePolicy) + if err != nil { + return nil, errors.Errorf("invalid signature policy: %s", signaturePolicy) + } + + applicationPolicy = &pb.ApplicationPolicy{ + Type: &pb.ApplicationPolicy_SignaturePolicy{ + SignaturePolicy: signaturePolicyEnvelope, + }, + } + } + + if channelConfigPolicy != "" { + applicationPolicy = &pb.ApplicationPolicy{ + Type: &pb.ApplicationPolicy_ChannelConfigPolicyReference{ + ChannelConfigPolicyReference: channelConfigPolicy, + }, + } + } + + return applicationPolicy, nil +} + func printResponseAsJSON(proposalResponse *pb.ProposalResponse, msg proto.Message, out io.Writer) error { err := proto.Unmarshal(proposalResponse.Response.Payload, msg) if err != nil {