Skip to content

Commit 8e991cc

Browse files
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 <[email protected]>
1 parent 84431e3 commit 8e991cc

16 files changed

+1498
-1026
lines changed

peer/chaincode/chaincode.go

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chaincode
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/hyperledger/fabric/flogging"
23+
"github.com/hyperledger/fabric/peer/common"
24+
"github.com/op/go-logging"
25+
"github.com/spf13/cobra"
26+
)
27+
28+
const (
29+
chainFuncName = "chaincode"
30+
)
31+
32+
var logger = logging.MustGetLogger("chaincodeCmd")
33+
34+
// Cmd returns the cobra command for Chaincode
35+
func Cmd() *cobra.Command {
36+
flags := chaincodeCmd.PersistentFlags()
37+
38+
flags.StringVarP(&chaincodeLang, "lang", "l", "golang",
39+
fmt.Sprintf("Language the %s is written in", chainFuncName))
40+
flags.StringVarP(&chaincodeCtorJSON, "ctor", "c", "{}",
41+
fmt.Sprintf("Constructor message for the %s in JSON format", chainFuncName))
42+
flags.StringVarP(&chaincodeAttributesJSON, "attributes", "a", "[]",
43+
fmt.Sprintf("User attributes for the %s in JSON format", chainFuncName))
44+
flags.StringVarP(&chaincodePath, "path", "p", common.UndefinedParamValue,
45+
fmt.Sprintf("Path to %s", chainFuncName))
46+
flags.StringVarP(&chaincodeName, "name", "n", common.UndefinedParamValue,
47+
fmt.Sprint("Name of the chaincode returned by the deploy transaction"))
48+
flags.StringVarP(&chaincodeUsr, "username", "u", common.UndefinedParamValue,
49+
fmt.Sprint("Username for chaincode operations when security is enabled"))
50+
flags.StringVarP(&customIDGenAlg, "tid", "t", common.UndefinedParamValue,
51+
fmt.Sprint("Name of a custom ID generation algorithm (hashing and decoding) e.g. sha256base64"))
52+
53+
chaincodeCmd.AddCommand(deployCmd())
54+
chaincodeCmd.AddCommand(invokeCmd())
55+
chaincodeCmd.AddCommand(queryCmd())
56+
57+
return chaincodeCmd
58+
}
59+
60+
// Chaincode-related variables.
61+
var (
62+
chaincodeLang string
63+
chaincodeCtorJSON string
64+
chaincodePath string
65+
chaincodeName string
66+
chaincodeUsr string
67+
chaincodeQueryRaw bool
68+
chaincodeQueryHex bool
69+
chaincodeAttributesJSON string
70+
customIDGenAlg string
71+
)
72+
73+
var chaincodeCmd = &cobra.Command{
74+
Use: chainFuncName,
75+
Short: fmt.Sprintf("%s specific commands.", chainFuncName),
76+
Long: fmt.Sprintf("%s specific commands.", chainFuncName),
77+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
78+
flogging.LoggingInit(chainFuncName)
79+
},
80+
}

peer/chaincode/common.go

+211
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
Copyright IBM Corp. 2016 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package chaincode
18+
19+
import (
20+
"encoding/json"
21+
"errors"
22+
"fmt"
23+
"io/ioutil"
24+
"os"
25+
"strings"
26+
27+
"github.com/hyperledger/fabric/core"
28+
"github.com/hyperledger/fabric/peer/common"
29+
"github.com/hyperledger/fabric/peer/util"
30+
pb "github.com/hyperledger/fabric/protos"
31+
"github.com/spf13/cobra"
32+
"github.com/spf13/viper"
33+
"golang.org/x/net/context"
34+
)
35+
36+
// chaincodeInvokeOrQuery invokes or queries the chaincode. If successful, the
37+
// INVOKE form prints the transaction ID on STDOUT, and the QUERY form prints
38+
// the query result on STDOUT. A command-line flag (-r, --raw) determines
39+
// whether the query result is output as raw bytes, or as a printable string.
40+
// The printable form is optionally (-x, --hex) a hexadecimal representation
41+
// of the query response. If the query response is NIL, nothing is output.
42+
func chaincodeInvokeOrQuery(cmd *cobra.Command, args []string, invoke bool) (err error) {
43+
44+
if err = checkChaincodeCmdParams(cmd); err != nil {
45+
return
46+
}
47+
48+
if chaincodeName == "" {
49+
err = errors.New("Name not given for invoke/query")
50+
return
51+
}
52+
53+
devopsClient, err := common.GetDevopsClient(cmd)
54+
if err != nil {
55+
err = fmt.Errorf("Error building %s: %s", chainFuncName, err)
56+
return
57+
}
58+
// Build the spec
59+
input := &pb.ChaincodeInput{}
60+
if err = json.Unmarshal([]byte(chaincodeCtorJSON), &input); err != nil {
61+
err = fmt.Errorf("Chaincode argument error: %s", err)
62+
return
63+
}
64+
65+
var attributes []string
66+
if err = json.Unmarshal([]byte(chaincodeAttributesJSON), &attributes); err != nil {
67+
err = fmt.Errorf("Chaincode argument error: %s", err)
68+
return
69+
}
70+
71+
chaincodeLang = strings.ToUpper(chaincodeLang)
72+
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value[chaincodeLang]),
73+
ChaincodeID: &pb.ChaincodeID{Name: chaincodeName}, CtorMsg: input, Attributes: attributes}
74+
75+
// If security is enabled, add client login token
76+
if core.SecurityEnabled() {
77+
if chaincodeUsr == common.UndefinedParamValue {
78+
err = errors.New("Must supply username for chaincode when security is enabled")
79+
return
80+
}
81+
82+
// Retrieve the CLI data storage path
83+
// Returns /var/openchain/production/client/
84+
localStore := util.GetCliFilePath()
85+
86+
// Check if the user is logged in before sending transaction
87+
if _, err = os.Stat(localStore + "loginToken_" + chaincodeUsr); err == nil {
88+
logger.Infof("Local user '%s' is already logged in. Retrieving login token.\n", chaincodeUsr)
89+
90+
// Read in the login token
91+
token, err := ioutil.ReadFile(localStore + "loginToken_" + chaincodeUsr)
92+
if err != nil {
93+
panic(fmt.Errorf("Fatal error when reading client login token: %s\n", err))
94+
}
95+
96+
// Add the login token to the chaincodeSpec
97+
spec.SecureContext = string(token)
98+
99+
// If privacy is enabled, mark chaincode as confidential
100+
if viper.GetBool("security.privacy") {
101+
logger.Info("Set confidentiality level to CONFIDENTIAL.\n")
102+
spec.ConfidentialityLevel = pb.ConfidentialityLevel_CONFIDENTIAL
103+
}
104+
} else {
105+
// Check if the token is not there and fail
106+
if os.IsNotExist(err) {
107+
err = fmt.Errorf("User '%s' not logged in. Use the 'login' command to obtain a security token.", chaincodeUsr)
108+
return
109+
}
110+
// Unexpected error
111+
panic(fmt.Errorf("Fatal error when checking for client login token: %s\n", err))
112+
}
113+
} else {
114+
if chaincodeUsr != common.UndefinedParamValue {
115+
logger.Warning("Username supplied but security is disabled.")
116+
}
117+
if viper.GetBool("security.privacy") {
118+
panic(errors.New("Privacy cannot be enabled as requested because security is disabled"))
119+
}
120+
}
121+
122+
// Build the ChaincodeInvocationSpec message
123+
invocation := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec}
124+
if customIDGenAlg != common.UndefinedParamValue {
125+
invocation.IdGenerationAlg = customIDGenAlg
126+
}
127+
128+
var resp *pb.Response
129+
if invoke {
130+
resp, err = devopsClient.Invoke(context.Background(), invocation)
131+
} else {
132+
resp, err = devopsClient.Query(context.Background(), invocation)
133+
}
134+
135+
if err != nil {
136+
if invoke {
137+
err = fmt.Errorf("Error invoking %s: %s\n", chainFuncName, err)
138+
} else {
139+
err = fmt.Errorf("Error querying %s: %s\n", chainFuncName, err)
140+
}
141+
return
142+
}
143+
if invoke {
144+
transactionID := string(resp.Msg)
145+
logger.Infof("Successfully invoked transaction: %s(%s)", invocation, transactionID)
146+
} else {
147+
logger.Infof("Successfully queried transaction: %s", invocation)
148+
if resp != nil {
149+
if chaincodeQueryRaw {
150+
if chaincodeQueryHex {
151+
err = errors.New("Options --raw (-r) and --hex (-x) are not compatible\n")
152+
return
153+
}
154+
os.Stdout.Write(resp.Msg)
155+
} else {
156+
if chaincodeQueryHex {
157+
logger.Debugf("%x\n", resp.Msg)
158+
} else {
159+
logger.Debug(string(resp.Msg))
160+
}
161+
}
162+
}
163+
}
164+
return nil
165+
}
166+
167+
func checkChaincodeCmdParams(cmd *cobra.Command) error {
168+
169+
if chaincodeName == common.UndefinedParamValue {
170+
if chaincodePath == common.UndefinedParamValue {
171+
return fmt.Errorf("Must supply value for %s path parameter.\n", chainFuncName)
172+
}
173+
}
174+
175+
// Check that non-empty chaincode parameters contain only Function and
176+
// Args keys. Type checking is done later when the JSON is actually
177+
// unmarshaled into a pb.ChaincodeInput. To better understand what's going
178+
// on here with JSON parsing see http://blog.golang.org/json-and-go -
179+
// Generic JSON with interface{}
180+
if chaincodeCtorJSON != "{}" {
181+
var f interface{}
182+
err := json.Unmarshal([]byte(chaincodeCtorJSON), &f)
183+
if err != nil {
184+
return fmt.Errorf("Chaincode argument error: %s", err)
185+
}
186+
m := f.(map[string]interface{})
187+
if len(m) != 2 {
188+
return fmt.Errorf("Non-empty JSON chaincode parameters must contain exactly 2 keys - 'Function' and 'Args'")
189+
}
190+
for k := range m {
191+
switch strings.ToLower(k) {
192+
case "function":
193+
case "args":
194+
default:
195+
return fmt.Errorf("Illegal chaincode key '%s' - must be either 'Function' or 'Args'", k)
196+
}
197+
}
198+
} else {
199+
return errors.New("Empty JSON chaincode parameters must contain exactly 2 keys - 'Function' and 'Args'")
200+
}
201+
202+
if chaincodeAttributesJSON != "[]" {
203+
var f interface{}
204+
err := json.Unmarshal([]byte(chaincodeAttributesJSON), &f)
205+
if err != nil {
206+
return fmt.Errorf("Chaincode argument error: %s", err)
207+
}
208+
}
209+
210+
return nil
211+
}

0 commit comments

Comments
 (0)