-
Notifications
You must be signed in to change notification settings - Fork 8.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Break up peer/main.go into multiple files.
Moving PR #2317 from github. Split peer/main.go into multiple packages desginated by each of the peer commands. The current file is >1100 lines and this will improve maintainability and pave the way for tests to be written. Also break up each of the subcommands into their own files, pending tests to be written so they can be disentangled from the global variables and also placed into seperate packages. Change-Id: I4549a44d20b9ce51f6fcd2d145dcf75f96c6476e Signed-off-by: Julian Carrivick <cjulian@au1.ibm.com>
- Loading branch information
1 parent
84431e3
commit 8e991cc
Showing
16 changed files
with
1,498 additions
and
1,026 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* | ||
Copyright IBM Corp. 2016 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package chaincode | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/hyperledger/fabric/flogging" | ||
"github.com/hyperledger/fabric/peer/common" | ||
"github.com/op/go-logging" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
const ( | ||
chainFuncName = "chaincode" | ||
) | ||
|
||
var logger = logging.MustGetLogger("chaincodeCmd") | ||
|
||
// Cmd returns the cobra command for Chaincode | ||
func Cmd() *cobra.Command { | ||
flags := chaincodeCmd.PersistentFlags() | ||
|
||
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(&chaincodeAttributesJSON, "attributes", "a", "[]", | ||
fmt.Sprintf("User attributes 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, | ||
fmt.Sprint("Name of the chaincode returned by the deploy transaction")) | ||
flags.StringVarP(&chaincodeUsr, "username", "u", common.UndefinedParamValue, | ||
fmt.Sprint("Username for chaincode operations when security is enabled")) | ||
flags.StringVarP(&customIDGenAlg, "tid", "t", common.UndefinedParamValue, | ||
fmt.Sprint("Name of a custom ID generation algorithm (hashing and decoding) e.g. sha256base64")) | ||
|
||
chaincodeCmd.AddCommand(deployCmd()) | ||
chaincodeCmd.AddCommand(invokeCmd()) | ||
chaincodeCmd.AddCommand(queryCmd()) | ||
|
||
return chaincodeCmd | ||
} | ||
|
||
// Chaincode-related variables. | ||
var ( | ||
chaincodeLang string | ||
chaincodeCtorJSON string | ||
chaincodePath string | ||
chaincodeName string | ||
chaincodeUsr string | ||
chaincodeQueryRaw bool | ||
chaincodeQueryHex bool | ||
chaincodeAttributesJSON string | ||
customIDGenAlg string | ||
) | ||
|
||
var chaincodeCmd = &cobra.Command{ | ||
Use: chainFuncName, | ||
Short: fmt.Sprintf("%s specific commands.", chainFuncName), | ||
Long: fmt.Sprintf("%s specific commands.", chainFuncName), | ||
PersistentPreRun: func(cmd *cobra.Command, args []string) { | ||
flogging.LoggingInit(chainFuncName) | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
/* | ||
Copyright IBM Corp. 2016 All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package chaincode | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"strings" | ||
|
||
"github.com/hyperledger/fabric/core" | ||
"github.com/hyperledger/fabric/peer/common" | ||
"github.com/hyperledger/fabric/peer/util" | ||
pb "github.com/hyperledger/fabric/protos" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
// chaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the | ||
// INVOKE form prints the transaction ID on 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. | ||
func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool) (err error) { | ||
|
||
if err = checkChaincodeCmdParams(cmd); err != nil { | ||
return | ||
} | ||
|
||
if chaincodeName == "" { | ||
err = errors.New("Name not given for invoke/query") | ||
return | ||
} | ||
|
||
devopsClient, err := common.GetDevopsClient(cmd) | ||
if err != nil { | ||
err = fmt.Errorf("Error building %s: %s", chainFuncName, err) | ||
return | ||
} | ||
// Build the spec | ||
input := &pb.ChaincodeInput{} | ||
if err = json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil { | ||
err = fmt.Errorf("Chaincode argument error: %s", err) | ||
return | ||
} | ||
|
||
var attributes []string | ||
if err = json.Unmarshal([]byte(chaincodeAttributesJSON), &attributes); err != nil { | ||
err = fmt.Errorf("Chaincode argument error: %s", err) | ||
return | ||
} | ||
|
||
chaincodeLang = strings.ToUpper(chaincodeLang) | ||
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]), | ||
ChaincodeID: &pb.ChaincodeID{Name: chaincodeName}, CtorMsg: input, Attributes: attributes} | ||
|
||
// If security is enabled, add client login token | ||
if core.SecurityEnabled() { | ||
if chaincodeUsr == common.UndefinedParamValue { | ||
err = errors.New("Must supply username for chaincode when security is enabled") | ||
return | ||
} | ||
|
||
// Retrieve the CLI data storage path | ||
// Returns /var/openchain/production/client/ | ||
localStore := util.GetCliFilePath() | ||
|
||
// Check if the user is logged in before sending transaction | ||
if _, err = os.Stat(localStore + "loginToken_" + chaincodeUsr); err == nil { | ||
logger.Infof("Local user '%s' is already logged in. Retrieving login token.\n", chaincodeUsr) | ||
|
||
// Read in the login token | ||
token, err := ioutil.ReadFile(localStore + "loginToken_" + chaincodeUsr) | ||
if err != nil { | ||
panic(fmt.Errorf("Fatal error when reading client login token: %s\n", err)) | ||
} | ||
|
||
// Add the login token to the chaincodeSpec | ||
spec.SecureContext = string(token) | ||
|
||
// If privacy is enabled, mark chaincode as confidential | ||
if viper.GetBool("security.privacy") { | ||
logger.Info("Set confidentiality level to CONFIDENTIAL.\n") | ||
spec.ConfidentialityLevel = pb.ConfidentialityLevel_CONFIDENTIAL | ||
} | ||
} else { | ||
// Check if the token is not there and fail | ||
if os.IsNotExist(err) { | ||
err = fmt.Errorf("User '%s' not logged in. Use the 'login' command to obtain a security token.", chaincodeUsr) | ||
return | ||
} | ||
// Unexpected error | ||
panic(fmt.Errorf("Fatal error when checking for client login token: %s\n", err)) | ||
} | ||
} else { | ||
if chaincodeUsr != common.UndefinedParamValue { | ||
logger.Warning("Username supplied but security is disabled.") | ||
} | ||
if viper.GetBool("security.privacy") { | ||
panic(errors.New("Privacy cannot be enabled as requested because security is disabled")) | ||
} | ||
} | ||
|
||
// Build the ChaincodeInvocationSpec message | ||
invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec} | ||
if customIDGenAlg != common.UndefinedParamValue { | ||
invocation.IdGenerationAlg = customIDGenAlg | ||
} | ||
|
||
var resp *pb.Response | ||
if invoke { | ||
resp, err = devopsClient.Invoke(context.Background(), invocation) | ||
} else { | ||
resp, err = devopsClient.Query(context.Background(), invocation) | ||
} | ||
|
||
if err != nil { | ||
if invoke { | ||
err = fmt.Errorf("Error invoking %s: %s\n", chainFuncName, err) | ||
} else { | ||
err = fmt.Errorf("Error querying %s: %s\n", chainFuncName, err) | ||
} | ||
return | ||
} | ||
if invoke { | ||
transactionID := string(resp.Msg) | ||
logger.Infof("Successfully invoked transaction: %s(%s)", invocation, transactionID) | ||
} else { | ||
logger.Infof("Successfully queried transaction: %s", invocation) | ||
if resp != nil { | ||
if chaincodeQueryRaw { | ||
if chaincodeQueryHex { | ||
err = errors.New("Options --raw (-r) and --hex (-x) are not compatible\n") | ||
return | ||
} | ||
os.Stdout.Write(resp.Msg) | ||
} else { | ||
if chaincodeQueryHex { | ||
logger.Debugf("%x\n", resp.Msg) | ||
} else { | ||
logger.Debug(string(resp.Msg)) | ||
} | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func checkChaincodeCmdParams(cmd *cobra.Command) error { | ||
|
||
if chaincodeName == common.UndefinedParamValue { | ||
if chaincodePath == common.UndefinedParamValue { | ||
return fmt.Errorf("Must supply value for %s path parameter.\n", chainFuncName) | ||
} | ||
} | ||
|
||
// Check that non-empty chaincode parameters contain only Function and | ||
// Args keys. 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 fmt.Errorf("Chaincode argument error: %s", err) | ||
} | ||
m := f.(map[string]interface{}) | ||
if len(m) != 2 { | ||
return fmt.Errorf("Non-empty JSON chaincode parameters must contain exactly 2 keys - 'Function' and 'Args'") | ||
} | ||
for k := range m { | ||
switch strings.ToLower(k) { | ||
case "function": | ||
case "args": | ||
default: | ||
return fmt.Errorf("Illegal chaincode key '%s' - must be either 'Function' or 'Args'", k) | ||
} | ||
} | ||
} else { | ||
return errors.New("Empty JSON chaincode parameters must contain exactly 2 keys - 'Function' and 'Args'") | ||
} | ||
|
||
if chaincodeAttributesJSON != "[]" { | ||
var f interface{} | ||
err := json.Unmarshal([]byte(chaincodeAttributesJSON), &f) | ||
if err != nil { | ||
return fmt.Errorf("Chaincode argument error: %s", err) | ||
} | ||
} | ||
|
||
return nil | ||
} |
Oops, something went wrong.