diff --git a/common/mocks/ledger/queryexecutor.go b/common/mocks/ledger/queryexecutor.go new file mode 100644 index 00000000000..f2144bccc44 --- /dev/null +++ b/common/mocks/ledger/queryexecutor.go @@ -0,0 +1,61 @@ +/* +Copyright IBM Corp. 2017 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 ledger + +import ( + "fmt" + + "github.com/hyperledger/fabric/common/ledger" +) + +type MockQueryExecutor struct { + // State keeps all namepspaces + State map[string]map[string][]byte +} + +func NewMockQueryExecutor(state map[string]map[string][]byte) *MockQueryExecutor { + return &MockQueryExecutor{ + State: state, + } +} + +func (m *MockQueryExecutor) GetState(namespace string, key string) ([]byte, error) { + ns := m.State[namespace] + if ns == nil { + return nil, fmt.Errorf("Could not retrieve namespace %s", namespace) + } + + return ns[key], nil +} + +func (m *MockQueryExecutor) GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error) { + return nil, nil + +} + +func (m *MockQueryExecutor) GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ledger.ResultsIterator, error) { + return nil, nil + +} + +func (m *MockQueryExecutor) ExecuteQuery(namespace, query string) (ledger.ResultsIterator, error) { + return nil, nil +} + +func (m *MockQueryExecutor) Done() { + +} diff --git a/core/common/sysccprovider/sysccprovider.go b/core/common/sysccprovider/sysccprovider.go index f70e7c97e9c..99d7bc1761f 100644 --- a/core/common/sysccprovider/sysccprovider.go +++ b/core/common/sysccprovider/sysccprovider.go @@ -16,7 +16,10 @@ limitations under the License. package sysccprovider -import "github.com/golang/protobuf/proto" +import ( + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric/core/ledger" +) // SystemChaincodeProvider provides an abstraction layer that is // used for different packages to interact with code in the @@ -29,6 +32,12 @@ type SystemChaincodeProvider interface { // IsSysCCAndNotInvokableCC2CC returns true if the supplied chaincode // is a system chaincode and is not invokable through a cc2cc invocation IsSysCCAndNotInvokableCC2CC(name string) bool + + // GetQueryExecutorForLedger returns a query executor for the + // ledger of the supplied channel. + // That's useful for system chaincodes that require unfettered + // access to the ledger + GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) } var sccFactory SystemChaincodeProviderFactory diff --git a/core/scc/lscc/lscc_test.go b/core/scc/lscc/lscc_test.go index 0f5e6ea7341..1772cdf362d 100644 --- a/core/scc/lscc/lscc_test.go +++ b/core/scc/lscc/lscc_test.go @@ -43,6 +43,7 @@ import ( putils "github.com/hyperledger/fabric/protos/utils" cutil "github.com/hyperledger/fabric/core/container/util" + "github.com/hyperledger/fabric/core/ledger" pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" ) @@ -67,6 +68,10 @@ func (c *mocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { return false } +func (c *mocksccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { + return nil, nil +} + func register(stub *shim.MockStub, ccname string) error { args := [][]byte{[]byte("register"), []byte(ccname)} if res := stub.MockInvoke("1", args); res.Status != shim.OK { diff --git a/core/scc/sccproviderimpl.go b/core/scc/sccproviderimpl.go index 552557c527d..e36ab4c3c65 100644 --- a/core/scc/sccproviderimpl.go +++ b/core/scc/sccproviderimpl.go @@ -17,7 +17,11 @@ limitations under the License. package scc import ( + "fmt" + "github.com/hyperledger/fabric/core/common/sysccprovider" + "github.com/hyperledger/fabric/core/ledger" + "github.com/hyperledger/fabric/core/peer" ) // sccProviderFactory implements the sysccprovider.SystemChaincodeProviderFactory @@ -50,3 +54,12 @@ func (c *sccProviderImpl) IsSysCC(name string) bool { func (c *sccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { return IsSysCCAndNotInvokableCC2CC(name) } + +func (c *sccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { + l := peer.GetLedger(cid) + if l == nil { + return nil, fmt.Errorf("Could not retrieve ledger for channel %s", cid) + } + + return l.NewQueryExecutor() +} diff --git a/core/scc/vscc/validator_onevalidsignature.go b/core/scc/vscc/validator_onevalidsignature.go index 91f8fe631cf..546c7291fb4 100644 --- a/core/scc/vscc/validator_onevalidsignature.go +++ b/core/scc/vscc/validator_onevalidsignature.go @@ -19,15 +19,20 @@ package vscc import ( "fmt" + "errors" + "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" "github.com/hyperledger/fabric/common/flogging" "github.com/hyperledger/fabric/core/chaincode/shim" + "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider" + "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" "github.com/hyperledger/fabric/core/scc/lscc" mspmgmt "github.com/hyperledger/fabric/msp/mgmt" "github.com/hyperledger/fabric/protos/common" + "github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset" pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" ) @@ -38,11 +43,16 @@ var logger = flogging.MustGetLogger("vscc") // which is to check the correctness of the read-write set and the endorsement // signatures type ValidatorOneValidSignature struct { + // sccprovider is the interface with which we call + // methods of the system chaincode package without + // import cycles + sccprovider sysccprovider.SystemChaincodeProvider } // Init is called once when the chaincode started the first time func (vscc *ValidatorOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Response { - // best practice to do nothing (or very little) in Init + vscc.sccprovider = sysccprovider.GetSystemChaincodeProvider() + return shim.Success(nil) } @@ -157,7 +167,9 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) // do some extra validation that is specific to lscc if hdrExt.ChaincodeId.Name == "lscc" { - err = vscc.ValidateLSCCInvocation(cap) + logger.Debugf("VSCC info: doing special validation for LSCC") + + err = vscc.ValidateLSCCInvocation(stub, chdr.ChannelId, env, cap) if err != nil { logger.Errorf("VSCC error: ValidateLSCCInvocation failed, err %s", err) return shim.Error(err.Error()) @@ -180,7 +192,49 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) return shim.Success(vodBytes) } -func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(cap *pb.ChaincodeActionPayload) error { +// checkInstantiationPolicy evaluates an instantiation policy against a signed proposal +func (vscc *ValidatorOneValidSignature) checkInstantiationPolicy(chainName string, env *common.Envelope, instantiationPolicy []byte) error { + // create a policy object from the policy bytes + mgr := mspmgmt.GetManagerForChain(chainName) + if mgr == nil { + return fmt.Errorf("MSP manager for channel %s is nil, aborting", chainName) + } + + npp := cauthdsl.NewPolicyProvider(mgr) + instPol, _, err := npp.NewPolicy(instantiationPolicy) + if err != nil { + return err + } + + logger.Debugf("VSCC info: checkInstantiationPolicy starts, policy is %#v", instPol) + + // get the payload + payl, err := utils.GetPayload(env) + if err != nil { + logger.Errorf("VSCC error: GetPayload failed, err %s", err) + return err + } + + // get the signature header + shdr, err := utils.GetSignatureHeader(payl.Header.SignatureHeader) + if err != nil { + return err + } + + // construct signed data we can evaluate the instantiation policy against + sd := []*common.SignedData{&common.SignedData{ + Data: env.Payload, + Identity: shdr.Creator, + Signature: env.Signature, + }} + err = instPol.Evaluate(sd) + if err != nil { + return fmt.Errorf("chaincode instantiation policy violated, error %s", err) + } + return nil +} + +func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(stub shim.ChaincodeStubInterface, chid string, env *common.Envelope, cap *pb.ChaincodeActionPayload) error { cpp, err := utils.GetChaincodeProposalPayload(cap.ChaincodeProposalPayload) if err != nil { logger.Errorf("VSCC error: GetChaincodeProposalPayload failed, err %s", err) @@ -194,8 +248,7 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(cap *pb.Chaincode return err } - if cis == nil || - cis.ChaincodeSpec == nil || + if cis.ChaincodeSpec == nil || cis.ChaincodeSpec.Input == nil || cis.ChaincodeSpec.Input.Args == nil { logger.Errorf("VSCC error: committing invalid vscc invocation") @@ -205,19 +258,194 @@ func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(cap *pb.Chaincode lsccFunc := string(cis.ChaincodeSpec.Input.Args[0]) lsccArgs := cis.ChaincodeSpec.Input.Args[1:] + logger.Debugf("VSCC info: ValidateLSCCInvocation acting on %s %#v", lsccFunc, lsccArgs) + switch lsccFunc { - case lscc.DEPLOY: - case lscc.UPGRADE: - logger.Infof("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs) + case lscc.UPGRADE, lscc.DEPLOY: + logger.Debugf("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs) + + if len(lsccArgs) < 2 || len(lsccArgs) > 5 { + return fmt.Errorf("Wrong number of arguments for invocation lscc(%s): expected between 2 and 5, received %d", lsccFunc, len(lsccArgs)) + } + + cdsArgs, err := utils.GetChaincodeDeploymentSpec(lsccArgs[1]) + if err != nil { + return fmt.Errorf("GetChaincodeDeploymentSpec error %s", err) + } + + if cdsArgs == nil || cdsArgs.ChaincodeSpec == nil || cdsArgs.ChaincodeSpec.ChaincodeId == nil || + cap.Action == nil || cap.Action.ProposalResponsePayload == nil { + return fmt.Errorf("VSCC error: invocation of lscc(%s) does not have appropriate arguments", lsccFunc) + } - // TODO: two more crs are expected to fill this gap, as explained in FAB-3155 - // 1) check that the invocation complies with the InstantiationPolicy - // 2) check that the read/write set is appropriate + // get the rwset + pRespPayload, err := utils.GetProposalResponsePayload(cap.Action.ProposalResponsePayload) + if err != nil { + return fmt.Errorf("GetProposalResponsePayload error %s", err) + } + if pRespPayload.Extension == nil { + return fmt.Errorf("nil pRespPayload.Extension") + } + respPayload, err := utils.GetChaincodeAction(pRespPayload.Extension) + if err != nil { + return fmt.Errorf("GetChaincodeAction error %s", err) + } + txRWSet := &rwsetutil.TxRwSet{} + if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { + return fmt.Errorf("txRWSet.FromProtoBytes error %s", err) + } + // extract the rwset for lscc + var lsccrwset *kvrwset.KVRWSet + for _, ns := range txRWSet.NsRwSets { + logger.Debugf("Namespace %s", ns.NameSpace) + if ns.NameSpace == "lscc" { + lsccrwset = ns.KvRwSet + break + } + } + + // retrieve from the ledger the entry for the chaincode at hand + cdLedger, ccExistsOnLedger, err := vscc.getInstantiatedCC(chid, cdsArgs.ChaincodeSpec.ChaincodeId.Name) + if err != nil { + return err + } + + /******************************************/ + /* security check 0 - validation of rwset */ + /******************************************/ + // there has to be one + if lsccrwset == nil { + return errors.New("No read write set for lscc was found") + } + // there can only be a single one + if len(lsccrwset.Writes) != 1 { + return errors.New("LSCC can only issue a single putState upon deploy/upgrade") + } + // the key name must be the chaincode id + if lsccrwset.Writes[0].Key != cdsArgs.ChaincodeSpec.ChaincodeId.Name { + return fmt.Errorf("Expected key %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, lsccrwset.Writes[0].Key) + } + // the value must be a ChaincodeData struct + cdRWSet := &ccprovider.ChaincodeData{} + err = proto.Unmarshal(lsccrwset.Writes[0].Value, cdRWSet) + if err != nil { + return fmt.Errorf("Unmarhsalling of ChaincodeData failed, error %s", err) + } + // the name must match + if cdRWSet.Name != cdsArgs.ChaincodeSpec.ChaincodeId.Name { + return fmt.Errorf("Expected cc name %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name, cdRWSet.Name) + } + // the version must match + if cdRWSet.Version != cdsArgs.ChaincodeSpec.ChaincodeId.Version { + return fmt.Errorf("Expected cc version %s, found %s", cdsArgs.ChaincodeSpec.ChaincodeId.Version, cdRWSet.Version) + } + // it must only write to 2 namespaces: LSCC's and the cc that we are deploying/upgrading + for _, ns := range txRWSet.NsRwSets { + if ns.NameSpace != "lscc" && ns.NameSpace != cdRWSet.Name && len(ns.KvRwSet.Writes) > 0 { + return fmt.Errorf("LSCC invocation is attempting to write to namespace %s", ns.NameSpace) + } + } + + logger.Debugf("Validating %s for cc %s version %s", lsccFunc, cdRWSet.Name, cdRWSet.Version) + + switch lsccFunc { + case lscc.DEPLOY: + /*****************************************************/ + /* security check 1 - check the instantiation policy */ + /*****************************************************/ + pol := cdRWSet.InstantiationPolicy + if pol != nil { + err = vscc.checkInstantiationPolicy(chid, env, pol) + if err != nil { + return err + } + } else { + // FIXME: this is only temporary until default policies + // are specified. We can then fail here once that's done. + // FIXME: could we actually pull the cds package from the + // file system to verify whether the policy that is specified + // here is the same as the one on disk? + // PROS: we prevent attacks where the policy is replaced + // CONS: this would be a point of non-determinism + logger.Debugf("No installation policy was specified, skipping checks") + } + + /******************************************************************/ + /* security check 2 - cc not in the LCCC table of instantiated cc */ + /******************************************************************/ + if ccExistsOnLedger { + return fmt.Errorf("Chaincode %s is already instantiated", cdsArgs.ChaincodeSpec.ChaincodeId.Name) + } + + case lscc.UPGRADE: + /**************************************************************/ + /* security check 1 - cc in the LCCC table of instantiated cc */ + /**************************************************************/ + if !ccExistsOnLedger { + return fmt.Errorf("Upgrading non-existent chaincode %s", cdsArgs.ChaincodeSpec.ChaincodeId.Name) + } + + /*****************************************************/ + /* security check 2 - check the instantiation policy */ + /*****************************************************/ + pol := cdLedger.InstantiationPolicy + if pol != nil { + err = vscc.checkInstantiationPolicy(chid, env, pol) + if err != nil { + return err + } + } else { + // FIXME: this is only temporary until default policies + // are specified. We can then fail here once that's done. + // FIXME: could we actually pull the cds package from the + // file system to verify whether the policy that is specified + // here is the same as the one on disk? + // PROS: we prevent attacks where the policy is replaced + // CONS: this would be a point of non-determinism + logger.Debugf("No installation policy was specified, skipping checks") + } + + /**********************************************************/ + /* security check 3 - existing cc's version was different */ + /**********************************************************/ + if cdLedger.Version == cdsArgs.ChaincodeSpec.ChaincodeId.Version { + return fmt.Errorf("Existing version of the cc on the ledger (%s) should be different from the upgraded one", cdsArgs.ChaincodeSpec.ChaincodeId.Version) + } + } + + // all is good! return nil default: return fmt.Errorf("VSCC error: committing an invocation of function %s of lscc is invalid", lsccFunc) } +} - return nil +func (vscc *ValidatorOneValidSignature) getInstantiatedCC(chid, ccid string) (cd *ccprovider.ChaincodeData, exists bool, err error) { + qe, err := vscc.sccprovider.GetQueryExecutorForLedger(chid) + if err != nil { + err = fmt.Errorf("Could not retrieve QueryExecutor for channel %s, error %s", chid, err) + return + } + defer qe.Done() + + bytes, err := qe.GetState("lscc", ccid) + if err != nil { + err = fmt.Errorf("Could not retrieve state for chaincode %s on channel %s, error %s", ccid, chid, err) + return + } + + if bytes == nil { + return + } + + cd = &ccprovider.ChaincodeData{} + err = proto.Unmarshal(bytes, cd) + if err != nil { + err = fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err) + return + } + + exists = true + return } diff --git a/core/scc/vscc/validator_onevalidsignature_test.go b/core/scc/vscc/validator_onevalidsignature_test.go index 0053db195be..ab1071c080a 100644 --- a/core/scc/vscc/validator_onevalidsignature_test.go +++ b/core/scc/vscc/validator_onevalidsignature_test.go @@ -22,16 +22,29 @@ import ( "fmt" "os" + "archive/tar" + "compress/gzip" + + "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" + lm "github.com/hyperledger/fabric/common/mocks/ledger" "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/chaincode/shim" + "github.com/hyperledger/fabric/core/common/ccpackage" + "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/common/sysccprovider" + cutils "github.com/hyperledger/fabric/core/container/util" + "github.com/hyperledger/fabric/core/ledger" + "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" + "github.com/hyperledger/fabric/core/policy" + "github.com/hyperledger/fabric/core/scc/lscc" "github.com/hyperledger/fabric/msp" mspmgmt "github.com/hyperledger/fabric/msp/mgmt" "github.com/hyperledger/fabric/msp/mgmt/testtools" "github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" + "github.com/stretchr/testify/assert" ) func createTx() (*common.Envelope, *peer.ProposalResponse, error) { @@ -56,6 +69,112 @@ func createTx() (*common.Envelope, *peer.ProposalResponse, error) { return env, presp, err } +func processSignedCDS(cds *peer.ChaincodeDeploymentSpec, policy *common.SignaturePolicyEnvelope) ([]byte, error) { + env, err := ccpackage.OwnerCreateSignedCCDepSpec(cds, policy, nil) + if err != nil { + return nil, fmt.Errorf("could not create package %s", err) + } + + b := utils.MarshalOrPanic(env) + + ccpack := &ccprovider.SignedCDSPackage{} + cd, err := ccpack.InitFromBuffer(b) + if err != nil { + return nil, fmt.Errorf("error owner creating package %s", err) + } + + if err = ccpack.PutChaincodeToFS(); err != nil { + return nil, fmt.Errorf("error putting package on the FS %s", err) + } + + cd.InstantiationPolicy = utils.MarshalOrPanic(policy) + + return utils.MarshalOrPanic(cd), nil +} + +func constructDeploymentSpec(name string, path string, version string, initArgs [][]byte, createFS bool) (*peer.ChaincodeDeploymentSpec, error) { + spec := &peer.ChaincodeSpec{Type: 1, ChaincodeId: &peer.ChaincodeID{Name: name, Path: path, Version: version}, Input: &peer.ChaincodeInput{Args: initArgs}} + + codePackageBytes := bytes.NewBuffer(nil) + gz := gzip.NewWriter(codePackageBytes) + tw := tar.NewWriter(gz) + + err := cutils.WriteBytesToPackage("src/garbage.go", []byte(name+path+version), tw) + if err != nil { + return nil, err + } + + tw.Close() + gz.Close() + + chaincodeDeploymentSpec := &peer.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes.Bytes()} + + if createFS { + err := ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec) + if err != nil { + return nil, err + } + } + + return chaincodeDeploymentSpec, nil +} + +func createCCDataRWset(nameK, nameV, version string, policy []byte) ([]byte, error) { + cd := &ccprovider.ChaincodeData{ + Name: nameV, + Version: version, + InstantiationPolicy: policy, + } + + cdbytes := utils.MarshalOrPanic(cd) + + rwsetBuilder := rwsetutil.NewRWSetBuilder() + rwsetBuilder.AddToWriteSet("lscc", nameK, cdbytes) + rwset := rwsetBuilder.GetTxReadWriteSet() + return rwset.ToProtoBytes() +} + +func createLSCCTx(ccname, ccver, f string, res []byte) (*common.Envelope, error) { + cds := &peer.ChaincodeDeploymentSpec{ + ChaincodeSpec: &peer.ChaincodeSpec{ + ChaincodeId: &peer.ChaincodeID{ + Name: ccname, + Version: ccver, + }, + Type: peer.ChaincodeSpec_GOLANG, + }, + } + + cdsBytes, err := proto.Marshal(cds) + if err != nil { + return nil, err + } + + cis := &peer.ChaincodeInvocationSpec{ + ChaincodeSpec: &peer.ChaincodeSpec{ + ChaincodeId: &peer.ChaincodeID{Name: "lscc"}, + Input: &peer.ChaincodeInput{ + Args: [][]byte{[]byte(f), []byte("barf"), cdsBytes}, + }, + Type: peer.ChaincodeSpec_GOLANG, + }, + } + + prop, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, sid) + if err != nil { + return nil, err + } + + ccid := &peer.ChaincodeID{Name: ccname, Version: ccver} + + presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, &peer.Response{Status: 200}, res, nil, ccid, nil, id) + if err != nil { + return nil, err + } + + return utils.CreateSignedTx(prop, id, presp) +} + func TestInit(t *testing.T) { v := new(ValidatorOneValidSignature) stub := shim.NewMockStub("validatoronevalidsignature", v) @@ -84,26 +203,22 @@ func TestInvoke(t *testing.T) { args := [][]byte{[]byte("dv")} if res := stub.MockInvoke("1", args); res.Status == shim.OK { t.Fatalf("vscc invoke should have failed") - return } args = [][]byte{[]byte("dv"), []byte("tx")} args[1] = nil if res := stub.MockInvoke("1", args); res.Status == shim.OK { t.Fatalf("vscc invoke should have failed") - return } tx, presp, err := createTx() if err != nil { t.Fatalf("createTx returned err %s", err) - return } envBytes, err := utils.GetBytesEnvelope(tx) if err != nil { t.Fatalf("GetBytesEnvelope returned err %s", err) - return } expectVod := &sysccprovider.VsccOutputData{ @@ -119,14 +234,12 @@ func TestInvoke(t *testing.T) { policy, err := getSignedByMSPMemberPolicy(mspid) if err != nil { t.Fatalf("failed getting policy, err %s", err) - return } args = [][]byte{[]byte("dv"), envBytes, policy} res := stub.MockInvoke("1", args) if res.Status != shim.OK { t.Fatalf("vscc invoke returned err %s", err) - return } if bytes.Compare(expectVodBytes, res.Payload) != 0 { @@ -138,22 +251,961 @@ func TestInvoke(t *testing.T) { policy, err = getSignedByMSPMemberPolicy("barf") if err != nil { t.Fatalf("failed getting policy, err %s", err) - return } args = [][]byte{[]byte("dv"), envBytes, policy} if res := stub.MockInvoke("1", args); res.Status == shim.OK { t.Fatalf("vscc invoke should have failed") - return } } -var id msp.SigningIdentity -var sid []byte -var mspid string -var chainId string = util.GetTestChainID() +func TestInvalidFunction(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + + res, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.GETCCDATA, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } +} + +func TestRWSetTooBig(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + + cd := &ccprovider.ChaincodeData{ + Name: ccname, + Version: ccver, + InstantiationPolicy: nil, + } + + cdbytes := utils.MarshalOrPanic(cd) + + rwsetBuilder := rwsetutil.NewRWSetBuilder() + rwsetBuilder.AddToWriteSet("lscc", ccname, cdbytes) + rwsetBuilder.AddToWriteSet("lscc", "spurious", []byte("spurious")) + rwset := rwsetBuilder.GetTxReadWriteSet() + res, err := rwset.ToProtoBytes() + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } +} + +func TestValidateDeployFail(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + + /*********************/ + /* test no write set */ + /*********************/ + + tx, err := createLSCCTx(ccname, ccver, lscc.DEPLOY, nil) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + /************************/ + /* test bogus write set */ + /************************/ + + rwsetBuilder := rwsetutil.NewRWSetBuilder() + rwsetBuilder.AddToWriteSet("lscc", ccname, []byte("barf")) + rwset := rwsetBuilder.GetTxReadWriteSet() + resBogus, err := rwset.ToProtoBytes() + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, resBogus) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + /***********************/ + /* test bad cc version */ + /***********************/ + + res, err := createCCDataRWset(ccname, ccname, ccver+".1", nil) + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + /********************/ + /* test bad cc name */ + /********************/ + + res, err = createCCDataRWset(ccname+".badbad", ccname, ccver, nil) + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + /**********************/ + /* test bad cc name 2 */ + /**********************/ + + res, err = createCCDataRWset(ccname, ccname+".badbad", ccver, nil) + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } + + /************************/ + /* test suprious writes */ + /************************/ + + cd := &ccprovider.ChaincodeData{ + Name: ccname, + Version: ccver, + InstantiationPolicy: nil, + } + + cdbytes := utils.MarshalOrPanic(cd) + rwsetBuilder = rwsetutil.NewRWSetBuilder() + rwsetBuilder.AddToWriteSet("lscc", ccname, cdbytes) + rwsetBuilder.AddToWriteSet("bogusbogus", "key", []byte("val")) + rwset = rwsetBuilder.GetTxReadWriteSet() + res, err = rwset.ToProtoBytes() + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } +} + +func TestAlreadyDeployed(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + ppath := lccctestpath + "/" + ccname + "." + ccver + + os.Remove(ppath) + + cds, err := constructDeploymentSpec(ccname, path, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) + if err != nil { + fmt.Printf("%s\n", err) + t.FailNow() + } + defer os.Remove(ppath) + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + args := [][]byte{[]byte("deploy"), []byte(ccname), b} + if res := stublccc.MockInvoke("1", args); res.Status != shim.OK { + fmt.Printf("%#v\n", res) + t.FailNow() + } + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.DEPLOY, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invocation should have failed") + } +} + +func TestValidateDeployOK(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + + res, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.Fatalf("vscc invoke returned err %s", res.Message) + } +} + +func TestValidateDeployWithPolicies(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + + /*********************************************/ + /* test 1: success with an accept-all policy */ + /*********************************************/ + + res, err := createCCDataRWset(ccname, ccname, ccver, cauthdsl.MarshaledAcceptAllPolicy) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.Fatalf("vscc invoke returned err %s", res.Message) + } + + /********************************************/ + /* test 2: failure with a reject-all policy */ + /********************************************/ + + res, err = createCCDataRWset(ccname, ccname, ccver, cauthdsl.MarshaledRejectAllPolicy) + assert.NoError(t, err) + + tx, err = createLSCCTx(ccname, ccver, lscc.DEPLOY, res) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err = utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err = getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } +} + +func TestInvalidUpgrade(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "2" + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.UPGRADE, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invocation should have failed") + } +} + +func TestValidateUpgradeOK(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + ppath := lccctestpath + "/" + ccname + "." + ccver + + os.Remove(ppath) + + cds, err := constructDeploymentSpec(ccname, path, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) + if err != nil { + fmt.Printf("%s\n", err) + t.FailNow() + } + defer os.Remove(ppath) + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + args := [][]byte{[]byte("deploy"), []byte(ccname), b} + if res := stublccc.MockInvoke("1", args); res.Status != shim.OK { + fmt.Printf("%#v\n", res) + t.FailNow() + } + + ccver = "2" + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.UPGRADE, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.Fatalf("vscc invoke returned err %s", res.Message) + } +} + +func TestInvalidateUpgradeBadVersion(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + ppath := lccctestpath + "/" + ccname + "." + ccver + + os.Remove(ppath) + + cds, err := constructDeploymentSpec(ccname, path, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true) + if err != nil { + fmt.Printf("%s\n", err) + t.FailNow() + } + defer os.Remove(ppath) + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + args := [][]byte{[]byte("deploy"), []byte(ccname), b} + if res := stublccc.MockInvoke("1", args); res.Status != shim.OK { + fmt.Printf("%#v\n", res) + t.FailNow() + } + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.UPGRADE, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invoke should have failed") + } +} + +func TestValidateUpgradeWithPoliciesOK(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + ppath := lccctestpath + "/" + ccname + "." + ccver + + os.Remove(ppath) + + cds, err := constructDeploymentSpec(ccname, path, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, false) + if err != nil { + fmt.Printf("%s\n", err) + t.FailNow() + } + _, err = processSignedCDS(cds, cauthdsl.AcceptAllPolicy) + assert.NoError(t, err) + defer os.Remove(ppath) + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + args := [][]byte{[]byte("deploy"), []byte(ccname), b} + if res := stublccc.MockInvoke("1", args); res.Status != shim.OK { + fmt.Printf("%#v\n", res) + t.FailNow() + } + + ccver = "2" + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.UPGRADE, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args = [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status != shim.OK { + t.Fatalf("vscc invoke returned err %s", res.Message) + } +} + +func TestValidateUpgradeWithPoliciesFail(t *testing.T) { + v := new(ValidatorOneValidSignature) + stub := shim.NewMockStub("validatoronevalidsignature", v) + + lccc := new(lscc.LifeCycleSysCC) + stublccc := shim.NewMockStub("lscc", lccc) + + State := make(map[string]map[string][]byte) + State["lscc"] = stublccc.State + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + stub.MockPeerChaincode("lscc", stublccc) + + r1 := stub.MockInit("1", [][]byte{}) + if r1.Status != shim.OK { + fmt.Println("Init failed", string(r1.Message)) + t.FailNow() + } + + r := stublccc.MockInit("1", [][]byte{}) + if r.Status != shim.OK { + fmt.Println("Init failed", string(r.Message)) + t.FailNow() + } + + ccname := "mycc" + ccver := "1" + path := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + ppath := lccctestpath + "/" + ccname + "." + ccver + + os.Remove(ppath) + + cds, err := constructDeploymentSpec(ccname, path, ccver, [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, false) + if err != nil { + fmt.Printf("%s\n", err) + t.FailNow() + } + cdbytes, err := processSignedCDS(cds, cauthdsl.RejectAllPolicy) + assert.NoError(t, err) + defer os.Remove(ppath) + var b []byte + if b, err = proto.Marshal(cds); err != nil || b == nil { + t.FailNow() + } + + // Simulate the lscc invocation whilst skipping the policy validation, + // otherwise we wouldn't be able to deply a chaincode with a reject all policy + stublccc.MockTransactionStart("barf") + err = stublccc.PutState(ccname, cdbytes) + assert.NoError(t, err) + stublccc.MockTransactionEnd("barf") + + ccver = "2" + + simresres, err := createCCDataRWset(ccname, ccname, ccver, nil) + assert.NoError(t, err) + + tx, err := createLSCCTx(ccname, ccver, lscc.UPGRADE, simresres) + if err != nil { + t.Fatalf("createTx returned err %s", err) + } + + envBytes, err := utils.GetBytesEnvelope(tx) + if err != nil { + t.Fatalf("GetBytesEnvelope returned err %s", err) + } + + // good path: signed by the right MSP + policy, err := getSignedByMSPMemberPolicy(mspid) + if err != nil { + t.Fatalf("failed getting policy, err %s", err) + } + + args := [][]byte{[]byte("dv"), envBytes, policy} + if res := stub.MockInvoke("1", args); res.Status == shim.OK { + t.Fatalf("vscc invocation should have failed") + } +} + +var id msp.SigningIdentity +var sid []byte +var mspid string +var chainId string = util.GetTestChainID() + +type mocksccProviderFactory struct { + Qe *lm.MockQueryExecutor +} + +func (c *mocksccProviderFactory) NewSystemChaincodeProvider() sysccprovider.SystemChaincodeProvider { + return &mocksccProviderImpl{Qe: c.Qe} +} + +type mocksccProviderImpl struct { + Qe *lm.MockQueryExecutor +} + +func (c *mocksccProviderImpl) IsSysCC(name string) bool { + return true +} + +func (c *mocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { + return false +} + +func (c *mocksccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { + return c.Qe, nil +} + +type mockPolicyCheckerFactory struct { +} + +func (c *mockPolicyCheckerFactory) NewPolicyChecker() policy.PolicyChecker { + return &mockPolicyChecker{} +} + +type mockPolicyChecker struct { +} + +func (c *mockPolicyChecker) CheckPolicy(channelID, policyName string, signedProp *peer.SignedProposal) error { + return nil +} + +func (c *mockPolicyChecker) CheckPolicyBySignedData(channelID, policyName string, sd []*common.SignedData) error { + return nil +} + +func (c *mockPolicyChecker) CheckPolicyNoChannel(policyName string, signedProp *peer.SignedProposal) error { + return nil +} + +var lccctestpath = "/tmp/lscc-validation-test" + +func TestMain(m *testing.M) { + ccprovider.SetChaincodesPath(lccctestpath) + sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{}) + policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{}) -func TestMain(m *testing.M) { var err error // setup the MSP manager so that we can sign/verify diff --git a/peer/chaincode/package.go b/peer/chaincode/package.go index eebb55e6556..5b6423e98d7 100644 --- a/peer/chaincode/package.go +++ b/peer/chaincode/package.go @@ -76,7 +76,7 @@ func packageCmd(cf *ChaincodeCmdFactory, cdsFact ccDepSpecFactory) *cobra.Comman func getInstantiationPolicy(policy string) (*pcommon.SignaturePolicyEnvelope, error) { p, err := cauthdsl.FromString(policy) if err != nil { - return nil, fmt.Errorf("Invalid policy %s", policy) + return nil, fmt.Errorf("Invalid policy %s, err %s", policy, err) } return p, nil }