From 22e2fc9fbc85eb71a5671e40913e9ee1f59ea575 Mon Sep 17 00:00:00 2001 From: Alessandro Sorniotti Date: Tue, 25 Apr 2017 16:23:53 +0200 Subject: [PATCH] [FAB-3269] properly honor endorsement policies This change set introduces proper validation of transactions: the write set of every transaction is validated according to the endorsement policy that was defined for the corresponding chaincode. Change-Id: Ie1cd22e1ad348d4fc1a2f8895f759955a461f416 Signed-off-by: Alessandro Sorniotti --- common/mocks/scc/sccprovider.go | 51 +++ .../committer/txvalidator/txvalidator_test.go | 77 ++-- core/committer/txvalidator/validator.go | 300 ++++++++----- core/committer/txvalidator/validator_test.go | 408 ++++++++++++++++++ core/common/sysccprovider/sysccprovider.go | 22 +- core/endorser/endorser.go | 2 +- core/mocks/ccprovider/ccprovider.go | 3 +- core/mocks/validator/validator.go | 8 +- core/peer/peer_test.go | 3 + core/scc/cscc/configure_test.go | 4 + core/scc/importsysccs.go | 4 +- core/scc/lscc/lscc_test.go | 35 +- core/scc/sccproviderimpl.go | 8 + core/scc/vscc/validator_onevalidsignature.go | 13 +- .../vscc/validator_onevalidsignature_test.go | 69 +-- protos/peer/transaction.pb.go | 119 ++--- protos/peer/transaction.proto | 5 + protos/utils/proputils.go | 20 - 18 files changed, 800 insertions(+), 351 deletions(-) create mode 100644 common/mocks/scc/sccprovider.go create mode 100644 core/committer/txvalidator/validator_test.go diff --git a/common/mocks/scc/sccprovider.go b/common/mocks/scc/sccprovider.go new file mode 100644 index 00000000000..12f01fb5f0f --- /dev/null +++ b/common/mocks/scc/sccprovider.go @@ -0,0 +1,51 @@ +/* +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 scc + +import ( + lm "github.com/hyperledger/fabric/common/mocks/ledger" + "github.com/hyperledger/fabric/core/common/sysccprovider" + "github.com/hyperledger/fabric/core/ledger" +) + +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 (name == "lscc") || (name == "escc") || (name == "vscc") || (name == "notext") +} + +func (c *mocksccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { + return (name == "escc") || (name == "vscc") +} + +func (c *mocksccProviderImpl) IsSysCCAndNotInvokableExternal(name string) bool { + return (name == "escc") || (name == "vscc") || (name == "notext") +} + +func (c *mocksccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { + return c.Qe, nil +} diff --git a/core/committer/txvalidator/txvalidator_test.go b/core/committer/txvalidator/txvalidator_test.go index 8b323b3745c..b401400ae09 100644 --- a/core/committer/txvalidator/txvalidator_test.go +++ b/core/committer/txvalidator/txvalidator_test.go @@ -23,7 +23,6 @@ import ( "github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/common/ledger/testutil" util2 "github.com/hyperledger/fabric/common/util" - "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/ledger/ledgermgmt" "github.com/hyperledger/fabric/core/ledger/util" ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" @@ -49,12 +48,6 @@ func TestBlockValidation(t *testing.T) { ledger, _ := ledgermgmt.CreateLedger(gb) defer ledger.Close() - chaincodeIns := &sysccprovider.ChaincodeInstance{ - ChaincodeName: "foo", - ChaincodeVersion: "v1", - ChainID: util2.GetTestChainID(), - } - simulator, _ := ledger.NewTxSimulator() simulator.SetState("ns1", "key1", []byte("value1")) simulator.SetState("ns1", "key2", []byte("value2")) @@ -63,15 +56,12 @@ func TestBlockValidation(t *testing.T) { simRes, _ := simulator.GetTxSimulationResults() - prespPaylBytes, err := testutil.ConstructBytesProposalResponsePayload("v1", simRes) + _, err := testutil.ConstructBytesProposalResponsePayload("v1", simRes) if err != nil { t.Fatalf("Could not construct ProposalResponsePayload bytes, err: %s", err) } - mockVsccValidator := &validator.MockVsccValidator{ - CIns: chaincodeIns, - RespPayl: prespPaylBytes, - } + mockVsccValidator := &validator.MockVsccValidator{} tValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, mockVsccValidator} bcInfo, _ := ledger.GetBlockchainInfo() @@ -85,27 +75,26 @@ func TestBlockValidation(t *testing.T) { txsfltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_VALID)) - // upgrade chaincode version - upgradeChaincodeIns := &sysccprovider.ChaincodeInstance{ - ChaincodeName: "foo", - ChaincodeVersion: "v2", // new version - ChainID: util2.GetTestChainID(), - } + /* - newMockVsccValidator := &validator.MockVsccValidator{ - CIns: upgradeChaincodeIns, - RespPayl: prespPaylBytes, - } - newTxValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, newMockVsccValidator} + a better way of testing this without all of the mocking was + implemented in validator_test.go + + newMockVsccValidator := &validator.MockVsccValidator{ + CIns: upgradeChaincodeIns, + RespPayl: prespPaylBytes, + } + newTxValidator := &txValidator{&mocktxvalidator.Support{LedgerVal: ledger}, newMockVsccValidator} - // generate new block - newBlock := testutil.ConstructBlock(t, 2, block.Header.Hash(), [][]byte{simRes}, true) // contains one tx with chaincode version v1 + // generate new block + newBlock := testutil.ConstructBlock(t, 2, block.Header.Hash(), [][]byte{simRes}, true) // contains one tx with chaincode version v1 - newTxValidator.Validate(newBlock) + newTxValidator.Validate(newBlock) - // tx should be invalided because of chaincode upgrade - txsfltr = util.TxValidationFlags(newBlock.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) - assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_EXPIRED_CHAINCODE)) + // tx should be invalided because of chaincode upgrade + txsfltr = util.TxValidationFlags(newBlock.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) + assert.True(t, txsfltr.IsSetTo(0, peer.TxValidationCode_EXPIRED_CHAINCODE)) + */ } func TestNewTxValidator_DuplicateTransactions(t *testing.T) { @@ -225,12 +214,12 @@ func TestGetTxCCInstance(t *testing.T) { payload, err := utils.GetPayload(env) assert.NoError(t, err) - expectInvokeCCIns := &sysccprovider.ChaincodeInstance{ + expectInvokeCCIns := &ChaincodeInstance{ ChainID: chainID, ChaincodeName: "lscc", ChaincodeVersion: "", } - expectUpgradeCCIns := &sysccprovider.ChaincodeInstance{ + expectUpgradeCCIns := &ChaincodeInstance{ ChainID: chainID, ChaincodeName: upgradeCCName, ChaincodeVersion: upgradeCCVersion, @@ -246,20 +235,20 @@ func TestGetTxCCInstance(t *testing.T) { } func TestInvalidTXsForUpgradeCC(t *testing.T) { - txsChaincodeNames := map[int]*sysccprovider.ChaincodeInstance{ - 0: &sysccprovider.ChaincodeInstance{"chain0", "cc0", "v0"}, // invoke cc0/chain0:v0, should not be affected by upgrade tx in other chain - 1: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx - 2: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v1, should be invalided by latter cc0/chain1 upgtade tx - 3: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx - 4: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v1"}, // invoke cc0/chain1:v1, should be invalided by cc1/chain1 upgrade tx - 5: &sysccprovider.ChaincodeInstance{"chain1", "cc1", "v0"}, // invoke cc1/chain1:v0, should not be affected by other chaincode upgrade tx - 6: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v2, should be invalided by latter cc0/chain1 upgtade tx - 7: &sysccprovider.ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v3 + txsChaincodeNames := map[int]*ChaincodeInstance{ + 0: &ChaincodeInstance{"chain0", "cc0", "v0"}, // invoke cc0/chain0:v0, should not be affected by upgrade tx in other chain + 1: &ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx + 2: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v1, should be invalided by latter cc0/chain1 upgtade tx + 3: &ChaincodeInstance{"chain1", "cc0", "v0"}, // invoke cc0/chain1:v0, should be invalided by cc1/chain1 upgrade tx + 4: &ChaincodeInstance{"chain1", "cc0", "v1"}, // invoke cc0/chain1:v1, should be invalided by cc1/chain1 upgrade tx + 5: &ChaincodeInstance{"chain1", "cc1", "v0"}, // invoke cc1/chain1:v0, should not be affected by other chaincode upgrade tx + 6: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v2, should be invalided by latter cc0/chain1 upgtade tx + 7: &ChaincodeInstance{"chain1", "lscc", ""}, // upgrade cc0/chain1 to v3 } - upgradedChaincodes := map[int]*sysccprovider.ChaincodeInstance{ - 2: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v1"}, - 6: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v2"}, - 7: &sysccprovider.ChaincodeInstance{"chain1", "cc0", "v3"}, + upgradedChaincodes := map[int]*ChaincodeInstance{ + 2: &ChaincodeInstance{"chain1", "cc0", "v1"}, + 6: &ChaincodeInstance{"chain1", "cc0", "v2"}, + 7: &ChaincodeInstance{"chain1", "cc0", "v3"}, } txsfltr := ledgerUtil.NewTxValidationFlags(8) diff --git a/core/committer/txvalidator/validator.go b/core/committer/txvalidator/validator.go index dbd2be40032..ecdc3d427f7 100644 --- a/core/committer/txvalidator/validator.go +++ b/core/committer/txvalidator/validator.go @@ -31,13 +31,13 @@ import ( ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" "github.com/hyperledger/fabric/msp" - "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" "github.com/op/go-logging" "github.com/hyperledger/fabric/common/cauthdsl" + "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" ) // Support provides all of the needed to evaluate the VSCC @@ -51,9 +51,6 @@ type Support interface { // Apply attempts to apply a configtx to become the new config Apply(configtx *common.ConfigEnvelope) error - // PolicyManager returns the policies.Manager for the channel - PolicyManager() policies.Manager - // GetMSPIDs returns the IDs for the application MSPs // that have been defined in the channel GetMSPIDs(cid string) []string @@ -70,14 +67,15 @@ type Validator interface { // and vscc execution, in order to increase // testability of txValidator type vsccValidator interface { - VSCCValidateTx(payload *common.Payload, envBytes []byte) (*sysccprovider.ChaincodeInstance, *sysccprovider.VsccOutputData, error) + VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) } // vsccValidator implementation which used to call // vscc chaincode and validate block transactions type vsccValidatorImpl struct { - support Support - ccprovider ccprovider.ChaincodeProvider + support Support + ccprovider ccprovider.ChaincodeProvider + sccprovider sysccprovider.SystemChaincodeProvider } // implementation of Validator interface, keeps @@ -88,6 +86,13 @@ type txValidator struct { vscc vsccValidator } +// ChaincodeInstance is unique identifier of chaincode instance +type ChaincodeInstance struct { + ChainID string + ChaincodeName string + ChaincodeVersion string +} + var logger *logging.Logger // package-level logger func init() { @@ -98,7 +103,11 @@ func init() { // NewTxValidator creates new transactions validator func NewTxValidator(support Support) Validator { // Encapsulates interface implementation - return &txValidator{support, &vsccValidatorImpl{support: support, ccprovider: ccprovider.GetChaincodeProvider()}} + return &txValidator{support, + &vsccValidatorImpl{ + support: support, + ccprovider: ccprovider.GetChaincodeProvider(), + sccprovider: sysccprovider.GetSystemChaincodeProvider()}} } func (v *txValidator) chainExists(chain string) bool { @@ -112,9 +121,9 @@ func (v *txValidator) Validate(block *common.Block) error { // Initialize trans as valid here, then set invalidation reason code upon invalidation below txsfltr := ledgerUtil.NewTxValidationFlags(len(block.Data.Data)) // txsChaincodeNames records all the invoked chaincodes by tx in a block - txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance) + txsChaincodeNames := make(map[int]*ChaincodeInstance) // upgradedChaincodes records all the chaincodes that are upgrded in a block - txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance) + txsUpgradedChaincodes := make(map[int]*ChaincodeInstance) for tIdx, d := range block.Data.Data { if d != nil { if env, err := utils.GetEnvelopeFromBlock(d); err != nil { @@ -164,18 +173,11 @@ func (v *txValidator) Validate(block *common.Block) error { // Validate tx with vscc and policy logger.Debug("Validating transaction vscc tx validate") - txcc, vod, err := v.vscc.VSCCValidateTx(payload, d) + err, cde := v.vscc.VSCCValidateTx(payload, d, env) if err != nil { txID := txID logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err) - txsfltr.SetFlag(tIdx, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE) - continue - } - - // Check chaincode version match the latest version in lscc - if err := v.validateChaincodeVersion(vod, txcc); err != nil { - logger.Errorf("Check chaincode version from transaction txId = %s returned error %s", txID, err) - txsfltr.SetFlag(tIdx, peer.TxValidationCode_EXPIRED_CHAINCODE) + txsfltr.SetFlag(tIdx, cde) continue } @@ -236,14 +238,14 @@ func (v *txValidator) generateCCKey(ccName, chainID string) string { } // invalidTXsForUpgradeCC invalid all txs that should be invalided because of chaincode upgrade txs -func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccprovider.ChaincodeInstance, txsUpgradedChaincodes map[int]*sysccprovider.ChaincodeInstance, txsfltr ledgerUtil.TxValidationFlags) ledgerUtil.TxValidationFlags { +func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*ChaincodeInstance, txsUpgradedChaincodes map[int]*ChaincodeInstance, txsfltr ledgerUtil.TxValidationFlags) ledgerUtil.TxValidationFlags { if len(txsUpgradedChaincodes) == 0 { return txsfltr } // Invalid former cc upgrade txs if there're two or more txs upgrade the same cc finalValidUpgradeTXs := make(map[string]int) - upgradedChaincodes := make(map[string]*sysccprovider.ChaincodeInstance) + upgradedChaincodes := make(map[string]*ChaincodeInstance) for tIdx, cc := range txsUpgradedChaincodes { if cc == nil { continue @@ -283,7 +285,7 @@ func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccpro return txsfltr } -func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upgradeCCIns *sysccprovider.ChaincodeInstance, err error) { +func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upgradeCCIns *ChaincodeInstance, err error) { // This is duplicated unpacking work, but make test easier. chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) if err != nil { @@ -291,12 +293,7 @@ func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upg } // Chain ID - chainID := chdr.ChannelId - if chainID == "" { - err := fmt.Errorf("transaction header does not contain an chain ID") - logger.Errorf("%s", err) - return nil, nil, err - } + chainID := chdr.ChannelId // it is guaranteed to be an existing channel by now // ChaincodeID hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) @@ -304,7 +301,7 @@ func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upg return nil, nil, err } invokeCC := hdrExt.ChaincodeId - invokeIns := &sysccprovider.ChaincodeInstance{ChainID: chainID, ChaincodeName: invokeCC.Name, ChaincodeVersion: invokeCC.Version} + invokeIns := &ChaincodeInstance{ChainID: chainID, ChaincodeName: invokeCC.Name, ChaincodeVersion: invokeCC.Version} // Transaction tx, err := utils.GetTransaction(payload.Data) @@ -348,79 +345,31 @@ func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upg return invokeIns, nil, nil } -func (v *txValidator) getUpgradeTxInstance(chainID string, cdsBytes []byte) (*sysccprovider.ChaincodeInstance, error) { +func (v *txValidator) getUpgradeTxInstance(chainID string, cdsBytes []byte) (*ChaincodeInstance, error) { cds, err := utils.GetChaincodeDeploymentSpec(cdsBytes) if err != nil { return nil, err } - return &sysccprovider.ChaincodeInstance{ + return &ChaincodeInstance{ ChainID: chainID, ChaincodeName: cds.ChaincodeSpec.ChaincodeId.Name, ChaincodeVersion: cds.ChaincodeSpec.ChaincodeId.Version, }, nil } -// validateChaincodeVersion check chaincode version in VsccOutputData returned by vscc match latest version in lscc -// Parameters should be guaranteed not nil by caller. -func (v *txValidator) validateChaincodeVersion(vod *sysccprovider.VsccOutputData, cIns *sysccprovider.ChaincodeInstance) error { - for _, prespBytes := range vod.ProposalResponseData { - // check chaincode version in ProposalResponse match latest version in lscc - cid, err := utils.GetChaincodeIDFromBytesProposalResponsePayload(prespBytes) - if err != nil { - logger.Errorf("Get ChaincodeID failed, err %s", err) - return err - } - if cid.Version != cIns.ChaincodeVersion { - err := fmt.Errorf("Chaincode %s:%s/%s didn't match %s:%s/%s in lscc", cid.Name, cid.Version, cIns.ChainID, cIns.ChaincodeName, cIns.ChaincodeVersion, cIns.ChainID) - logger.Errorf(err.Error()) - return err - } - } - - return nil -} - // GetInfoForValidate gets the ChaincodeInstance(with latest version) of tx, vscc and policy from lscc -func (v *vsccValidatorImpl) GetInfoForValidate(payload *common.Payload) (*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) { - // get channel header - chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) - if err != nil { - return nil, nil, nil, err - } - - // Chain ID - chainID := chdr.ChannelId - if chainID == "" { - err := fmt.Errorf("transaction header does not contain an chain ID") - logger.Errorf("%s", err) - return nil, nil, nil, err - } - - // Get transaction id - txid := chdr.TxId - if txid == "" { - err := fmt.Errorf("transaction header does not contain transaction ID") - logger.Errorf("%s", err) - return nil, nil, nil, err - } - - // get header extensions so we have the visibility field - hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) - if err != nil { - return nil, nil, nil, err - } - - cc := &sysccprovider.ChaincodeInstance{ChainID: chainID} - vscc := &sysccprovider.ChaincodeInstance{ChainID: chainID} +func (v *vsccValidatorImpl) GetInfoForValidate(txid, chID, ccID string) (*ChaincodeInstance, *ChaincodeInstance, []byte, error) { + cc := &ChaincodeInstance{ChainID: chID} + vscc := &ChaincodeInstance{ChainID: chID} var policy []byte - if hdrExt.ChaincodeId.Name != "lscc" { + if ccID != "lscc" { // when we are validating any chaincode other than // LSCC, we need to ask LSCC to give us the name // of VSCC and of the policy that should be used // obtain name of the VSCC and the policy from LSCC - cd, err := v.getCDataForCC(hdrExt.ChaincodeId.Name) + cd, err := v.getCDataForCC(ccID) if err != nil { logger.Errorf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err) return nil, nil, nil, err @@ -436,7 +385,7 @@ func (v *vsccValidatorImpl) GetInfoForValidate(payload *common.Payload) (*sysccp cc.ChaincodeName = "lscc" cc.ChaincodeVersion = coreUtil.GetSysCCVersion() vscc.ChaincodeName = "vscc" - policy = cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chainID)) + policy = cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chID)) } // Get vscc version @@ -445,64 +394,189 @@ func (v *vsccValidatorImpl) GetInfoForValidate(payload *common.Payload) (*sysccp return cc, vscc, policy, nil } -// VSCCValidateTx validates tx with given vscc and policy, returns latest ChaincodeInstance in lscc and VsccOutputData if validate successfully. -func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte) (*sysccprovider.ChaincodeInstance, *sysccprovider.VsccOutputData, error) { +func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) { + // get header extensions so we have the chaincode ID + hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) + if err != nil { + return err, peer.TxValidationCode_BAD_HEADER_EXTENSION + } + // get channel header chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) if err != nil { - return nil, nil, err + return err, peer.TxValidationCode_BAD_CHANNEL_HEADER + } + + /* obtain the list of namespaces we're writing stuff to; + at first, we establish a few facts about this invocation: + 1) which namespaces does it write to? + 2) does it write to LSCC's namespace? + 3) does it write to any cc that cannot be invoked? */ + wrNamespace := []string{} + writesToLSCC := false + writesToNonInvokableSCC := false + respPayload, err := utils.GetActionFromEnvelope(envBytes) + if err != nil { + return fmt.Errorf("GetActionFromEnvelope failed, error %s", err), peer.TxValidationCode_BAD_RESPONSE_PAYLOAD + } + txRWSet := &rwsetutil.TxRwSet{} + if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { + return fmt.Errorf("txRWSet.FromProtoBytes failed, error %s", err), peer.TxValidationCode_BAD_RWSET } + for _, ns := range txRWSet.NsRwSets { + if len(ns.KvRwSet.Writes) > 0 { + wrNamespace = append(wrNamespace, ns.NameSpace) + + if !writesToLSCC && ns.NameSpace == "lscc" { + writesToLSCC = true + } - // Get transaction id - txid := chdr.TxId - if txid == "" { - err := fmt.Errorf("transaction header does not contain transaction ID") + if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableCC2CC(ns.NameSpace) { + writesToNonInvokableSCC = true + } + + if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableExternal(ns.NameSpace) { + writesToNonInvokableSCC = true + } + } + } + + // get name and version of the cc we invoked + ccID := hdrExt.ChaincodeId.Name + ccVer := respPayload.ChaincodeId.Version + + // sanity check on ccID + if ccID == "" { + err := fmt.Errorf("invalid chaincode ID") logger.Errorf("%s", err) - return nil, nil, err + return err, peer.TxValidationCode_INVALID_OTHER_REASON } + if ccID != respPayload.ChaincodeId.Name { + err := fmt.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name) + logger.Errorf("%s", err) + return err, peer.TxValidationCode_INVALID_OTHER_REASON + } + // sanity check on ccver + if ccVer == "" { + err := fmt.Errorf("invalid chaincode version") + logger.Errorf("%s", err) + return err, peer.TxValidationCode_INVALID_OTHER_REASON + } + + // we've gathered all the info required to proceed to validation; + // validation will behave differently depending on the type of + // chaincode (system vs. application) + + if !v.sccprovider.IsSysCC(ccID) { + // if we're here, we know this is an invocation of an application chaincode; + // first of all, we make sure that: + // 1) we don't write to LSCC - an application chaincode is free to invoke LSCC + // for instance to get information about itself or another chaincode; however + // these legitimate invocations only ready from LSCC's namespace; currently + // only two functions of LSCC write to its namespace: deploy and upgrade and + // neither should be used by an application chaincode + if writesToLSCC { + return fmt.Errorf("Chaincode %s attempted to write to the namespace of LSCC", ccID), + peer.TxValidationCode_ILLEGAL_WRITESET + } + // 2) we don't write to the namespace of a chaincode that we cannot invoke - if + // the chaincode cannot be invoked in the first place, there's no legitimate + // way in which a transaction has a write set that writes to it; additionally + // we don't have any means of verifying whether the transaction had the rights + // to perform that write operation because in v1, system chaincodes do not have + // any endorsement policies to speak of. So if the chaincode can't be invoked + // it can't be written to by an invocation of an application chaincode + if writesToNonInvokableSCC { + return fmt.Errorf("Chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked", ccID), + peer.TxValidationCode_ILLEGAL_WRITESET + } + + // validate *EACH* read write set according to its chaincode's endorsement policy + for _, ns := range wrNamespace { + // Get latest chaincode version, vscc and validate policy + txcc, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ns) + if err != nil { + logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err) + return err, peer.TxValidationCode_INVALID_OTHER_REASON + } + // if the namespace corresponds to the cc that was originally + // invoked, we check that the version of the cc that was + // invoked corresponds to the version that lscc has returned + if ns == ccID && txcc.ChaincodeVersion != ccVer { + err := fmt.Errorf("Chaincode %s:%s/%s didn't match %s:%s/%s in lscc", ccID, ccVer, chdr.ChannelId, txcc.ChaincodeName, txcc.ChaincodeVersion, chdr.ChannelId) + logger.Errorf(err.Error()) + return err, peer.TxValidationCode_EXPIRED_CHAINCODE + } + + // do VSCC validation + if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, chdr.ChannelId, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil { + return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err), + peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE + } + } + } else { + // make sure that we can invoke this system chaincode - if the chaincode + // cannot be invoked through a proposal to this peer, we have to drop the + // transaction; if we didn't, we wouldn't know how to decide whether it's + // valid or not because in v1, system chaincodes have no endorsement policy + if v.sccprovider.IsSysCCAndNotInvokableExternal(ccID) { + return fmt.Errorf("Committing an invocation of cc %s is illegal", ccID), + peer.TxValidationCode_ILLEGAL_WRITESET + } + + // Get latest chaincode version, vscc and validate policy + _, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ccID) + if err != nil { + logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err) + return err, peer.TxValidationCode_INVALID_OTHER_REASON + } + + // validate the transaction as an invocation of this system chaincode; + // vscc will have to do custom validation for this system chaincode + // currently, VSCC does custom validation for LSCC only; if an hlf + // user creates a new system chaincode which is invokable from the outside + // they have to modify VSCC to provide appropriate validation + if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, vscc.ChainID, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil { + return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err), + peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE + } + } + + return nil, peer.TxValidationCode_VALID +} + +func (v *vsccValidatorImpl) VSCCValidateTxForCC(envBytes []byte, txid, chid, vsccName, vsccVer string, policy []byte) error { ctxt, err := v.ccprovider.GetContext(v.support.Ledger()) if err != nil { logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err) - return nil, nil, err + return err } defer v.ccprovider.ReleaseContext() - // Get latest chaincode version, vscc and validate policy - txcc, vscc, policy, err := v.GetInfoForValidate(payload) - if err != nil { - logger.Errorf("GetInfoForValidate for txId = %s returned error %s", txid, err) - return nil, nil, err - } - // build arguments for VSCC invocation // args[0] - function name (not used now) // args[1] - serialized Envelope // args[2] - serialized policy args := [][]byte{[]byte(""), envBytes, policy} + // get context to invoke VSCC vscctxid := coreUtil.GenerateUUID() - vscccid := v.ccprovider.GetCCContext("", vscc.ChaincodeName, vscc.ChaincodeVersion, vscctxid, true, nil, nil) + cccid := v.ccprovider.GetCCContext(chid, vsccName, vsccVer, vscctxid, true, nil, nil) // invoke VSCC - logger.Debug("Invoking VSCC txid", txid, "chaindID", vscc.ChainID) - res, _, err := v.ccprovider.ExecuteChaincode(ctxt, vscccid, args) + logger.Debug("Invoking VSCC txid", txid, "chaindID", chid) + res, _, err := v.ccprovider.ExecuteChaincode(ctxt, cccid, args) if err != nil { logger.Errorf("Invoke VSCC failed for transaction txid=%s, error %s", txid, err) - return nil, nil, err + return err } if res.Status != shim.OK { logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, res.Message) - return nil, nil, fmt.Errorf("%s", res.Message) + return fmt.Errorf("%s", res.Message) } - vod := &sysccprovider.VsccOutputData{} - err = proto.Unmarshal(res.Payload, vod) - if err != nil { - return nil, nil, fmt.Errorf("Unmarshal VsccOutputdata for transaction txid=%s failed, error: %s", txid, err) - } - - return txcc, vod, nil + return nil } func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) { diff --git a/core/committer/txvalidator/validator_test.go b/core/committer/txvalidator/validator_test.go new file mode 100644 index 00000000000..e92e282f46d --- /dev/null +++ b/core/committer/txvalidator/validator_test.go @@ -0,0 +1,408 @@ +/* +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 txvalidator + +import ( + "fmt" + "os" + "testing" + + "github.com/hyperledger/fabric/common/cauthdsl" + ctxt "github.com/hyperledger/fabric/common/configtx/test" + "github.com/hyperledger/fabric/common/ledger/testutil" + "github.com/hyperledger/fabric/common/mocks/scc" + "github.com/hyperledger/fabric/common/util" + ccp "github.com/hyperledger/fabric/core/common/ccprovider" + "github.com/hyperledger/fabric/core/common/sysccprovider" + "github.com/hyperledger/fabric/core/ledger" + "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" + "github.com/hyperledger/fabric/core/ledger/ledgermgmt" + lutils "github.com/hyperledger/fabric/core/ledger/util" + "github.com/hyperledger/fabric/core/mocks/ccprovider" + "github.com/hyperledger/fabric/msp" + "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/spf13/viper" + "github.com/stretchr/testify/assert" +) + +func setupLedgerAndValidator(t *testing.T) (ledger.PeerLedger, Validator) { + viper.Set("peer.fileSystemPath", "/tmp/fabric/validatortest") + ledgermgmt.InitializeTestEnv() + gb, err := ctxt.MakeGenesisBlock("TestLedger") + assert.NoError(t, err) + theLedger, err := ledgermgmt.CreateLedger(gb) + assert.NoError(t, err) + theValidator := NewTxValidator(&mockSupport{l: theLedger}) + + return theLedger, theValidator +} + +func createRWset(t *testing.T, ccnames ...string) []byte { + rwsetBuilder := rwsetutil.NewRWSetBuilder() + for _, ccname := range ccnames { + rwsetBuilder.AddToWriteSet(ccname, "key", []byte("value")) + } + rwset := rwsetBuilder.GetTxReadWriteSet() + rws, err := rwset.ToProtoBytes() + assert.NoError(t, err) + return rws +} + +func getProposal(ccID string) (*peer.Proposal, error) { + cis := &peer.ChaincodeInvocationSpec{ + ChaincodeSpec: &peer.ChaincodeSpec{ + ChaincodeId: &peer.ChaincodeID{Name: ccID, Version: ccVersion}, + Input: &peer.ChaincodeInput{Args: [][]byte{[]byte("func")}}, + Type: peer.ChaincodeSpec_GOLANG}} + + proposal, _, err := utils.CreateProposalFromCIS(common.HeaderType_ENDORSER_TRANSACTION, util.GetTestChainID(), cis, signerSerialized) + return proposal, err +} + +const ccVersion = "1.0" + +func getEnv(ccID string, res []byte, t *testing.T) *common.Envelope { + // get a toy proposal + prop, err := getProposal(ccID) + assert.NoError(t, err) + + response := &peer.Response{Status: 200} + + // endorse it to get a proposal response + presp, err := utils.CreateProposalResponse(prop.Header, prop.Payload, response, res, nil, &peer.ChaincodeID{Name: ccID, Version: ccVersion}, nil, signer) + assert.NoError(t, err) + + // assemble a transaction from that proposal and endorsement + tx, err := utils.CreateSignedTx(prop, signer, presp) + assert.NoError(t, err) + + return tx +} + +func putCCInfoWithVSCCAndVer(theLedger ledger.PeerLedger, ccname, vscc, ver string, policy []byte, t *testing.T) { + cd := &ccp.ChaincodeData{ + Name: ccname, + Version: ver, + Vscc: vscc, + Policy: policy, + } + + cdbytes := utils.MarshalOrPanic(cd) + + simulator, err := theLedger.NewTxSimulator() + assert.NoError(t, err) + simulator.SetState("lscc", ccname, cdbytes) + simulator.Done() + + simRes, err := simulator.GetTxSimulationResults() + assert.NoError(t, err) + block0 := testutil.ConstructBlock(t, 1, []byte("hash"), [][]byte{simRes}, true) + err = theLedger.Commit(block0) + assert.NoError(t, err) +} + +func putCCInfo(theLedger ledger.PeerLedger, ccname string, policy []byte, t *testing.T) { + putCCInfoWithVSCCAndVer(theLedger, ccname, "vscc", ccVersion, policy, t) +} + +type mockSupport struct { + l ledger.PeerLedger +} + +func (m *mockSupport) Ledger() ledger.PeerLedger { + return m.l +} + +func (m *mockSupport) MSPManager() msp.MSPManager { + return mgmt.GetManagerForChain(util.GetTestChainID()) +} + +func (m *mockSupport) Apply(configtx *common.ConfigEnvelope) error { + return nil +} + +func (m *mockSupport) GetMSPIDs(cid string) []string { + return []string{"DEFAULT"} +} + +func assertInvalid(block *common.Block, t *testing.T, code peer.TxValidationCode) { + txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) + assert.True(t, txsFilter.IsInvalid(0)) + assert.True(t, txsFilter.IsSetTo(0, code)) +} + +func assertValid(block *common.Block, t *testing.T) { + txsFilter := lutils.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) + assert.False(t, txsFilter.IsInvalid(0)) +} + +func TestInvokeBadRWSet(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + tx := getEnv(ccID, []byte("barf"), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_BAD_RWSET) +} + +func TestInvokeNoPolicy(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, nil, t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON) +} + +func TestInvokeOK(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertValid(b, t) +} + +func TestInvokeOKSCC(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "lscc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertValid(b, t) +} + +func TestInvokeNOKWritesToLSCC(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID, "lscc"), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET) +} + +func TestInvokeNOKWritesToESCC(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID, "escc"), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET) +} + +func TestInvokeNOKWritesToNotExt(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID, "notext"), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET) +} + +func TestInvokeNOKInvokesNotExt(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "notext" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_ILLEGAL_WRITESET) +} + +func TestInvokeNOKInvokesEmptyCCName(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON) +} + +func TestInvokeNOKExpiredCC(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfoWithVSCCAndVer(l, ccID, "vscc", "badversion", cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_EXPIRED_CHAINCODE) +} + +func TestInvokeNOKBogusActions(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfo(l, ccID, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, []byte("barf"), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_BAD_RWSET) +} + +func TestInvokeNOKCCDoesntExist(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON) +} + +func TestInvokeNOKVSCCUnspecified(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + ccID := "mycc" + + putCCInfoWithVSCCAndVer(l, ccID, "", ccVersion, cauthdsl.SignedByAnyMember([]string{"DEFAULT"}), t) + + tx := getEnv(ccID, createRWset(t, ccID), t) + b := &common.Block{Data: &common.BlockData{Data: [][]byte{utils.MarshalOrPanic(tx)}}} + + err := v.Validate(b) + assert.NoError(t, err) + assertInvalid(b, t, peer.TxValidationCode_INVALID_OTHER_REASON) +} + +func TestInvokeNoBlock(t *testing.T) { + l, v := setupLedgerAndValidator(t) + defer ledgermgmt.CleanupTestEnv() + defer l.Close() + + err := v.Validate(&common.Block{Data: &common.BlockData{Data: [][]byte{}}}) + assert.NoError(t, err) +} + +var signer msp.SigningIdentity +var signerSerialized []byte + +func TestMain(m *testing.M) { + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{}) + ccp.RegisterChaincodeProviderFactory(&ccprovider.MockCcProviderFactory{}) + + msptesttools.LoadMSPSetupForTesting() + + var err error + signer, err = mgmt.GetLocalMSP().GetDefaultSigningIdentity() + if err != nil { + fmt.Println("Could not get signer") + os.Exit(-1) + return + } + + signerSerialized, err = signer.Serialize() + if err != nil { + fmt.Println("Could not serialize identity") + os.Exit(-1) + return + } + + os.Exit(m.Run()) +} diff --git a/core/common/sysccprovider/sysccprovider.go b/core/common/sysccprovider/sysccprovider.go index f72149d7839..3de927e04df 100644 --- a/core/common/sysccprovider/sysccprovider.go +++ b/core/common/sysccprovider/sysccprovider.go @@ -17,7 +17,6 @@ limitations under the License. package sysccprovider import ( - "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/ledger" ) @@ -33,6 +32,10 @@ type SystemChaincodeProvider interface { // is a system chaincode and is not invokable through a cc2cc invocation IsSysCCAndNotInvokableCC2CC(name string) bool + // IsSysCCAndNotInvokable returns true if the supplied chaincode + // is a system chaincode and is not invokable through a proposal + IsSysCCAndNotInvokableExternal(name string) bool + // GetQueryExecutorForLedger returns a query executor for the // ledger of the supplied channel. // That's useful for system chaincodes that require unfettered @@ -74,20 +77,3 @@ type ChaincodeInstance struct { func (ci *ChaincodeInstance) String() string { return ci.ChainID + "." + ci.ChaincodeName + "#" + ci.ChaincodeVersion } - -// VsccOutputData contains all the data returned from vscc. -type VsccOutputData struct { - // ProposalResponse bytes array validated by vscc - ProposalResponseData [][]byte `protobuf:"bytes,1,rep,name=proposalResponseData,proto3"` -} - -//implement functions needed from proto.Message for proto's mar/unmarshal functions - -//Reset resets -func (vod *VsccOutputData) Reset() { *vod = VsccOutputData{} } - -//String convers to string -func (vod *VsccOutputData) String() string { return proto.CompactTextString(vod) } - -//ProtoMessage just exists to make proto happy -func (*VsccOutputData) ProtoMessage() {} diff --git a/core/endorser/endorser.go b/core/endorser/endorser.go index a6e1e12faa2..ba13a6511e5 100644 --- a/core/endorser/endorser.go +++ b/core/endorser/endorser.go @@ -316,7 +316,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro } // block invocations to security-sensitive system chaincodes - if syscc.IsSysCCAndNotInvokable(hdrExt.ChaincodeId.Name) { + if syscc.IsSysCCAndNotInvokableExternal(hdrExt.ChaincodeId.Name) { endorserLogger.Errorf("ProcessProposal error: an attempt was made by %#v to invoke system chaincode %s", shdr.Creator, hdrExt.ChaincodeId.Name) err = fmt.Errorf("Chaincode %s cannot be invoked through a proposal", hdrExt.ChaincodeId.Name) diff --git a/core/mocks/ccprovider/ccprovider.go b/core/mocks/ccprovider/ccprovider.go index ca5d64cd44d..0ac8e948543 100644 --- a/core/mocks/ccprovider/ccprovider.go +++ b/core/mocks/ccprovider/ccprovider.go @@ -19,6 +19,7 @@ package ccprovider import ( "context" + "github.com/hyperledger/fabric/core/chaincode/shim" "github.com/hyperledger/fabric/core/common/ccprovider" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/protos/peer" @@ -58,7 +59,7 @@ func (c *mockCcProviderImpl) GetCCValidationInfoFromLSCC(ctxt context.Context, t // ExecuteChaincode does nothing func (c *mockCcProviderImpl) ExecuteChaincode(ctxt context.Context, cccid interface{}, args [][]byte) (*peer.Response, *peer.ChaincodeEvent, error) { - return nil, nil, nil + return &peer.Response{Status: shim.OK}, nil, nil } // Execute executes the chaincode given context and spec (invocation or deploy) diff --git a/core/mocks/validator/validator.go b/core/mocks/validator/validator.go index ffe54eea67c..49fc5b54ecd 100644 --- a/core/mocks/validator/validator.go +++ b/core/mocks/validator/validator.go @@ -17,8 +17,8 @@ limitations under the License. package validator import ( - "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/protos/common" + "github.com/hyperledger/fabric/protos/peer" ) // MockValidator implements a mock validation useful for testing @@ -32,11 +32,9 @@ func (m *MockValidator) Validate(block *common.Block) error { // MockVsccValidator is a mock implementation of the VSCC validation interface type MockVsccValidator struct { - CIns *sysccprovider.ChaincodeInstance - RespPayl []byte } // VSCCValidateTx does nothing -func (v *MockVsccValidator) VSCCValidateTx(payload *common.Payload, envBytes []byte) (*sysccprovider.ChaincodeInstance, *sysccprovider.VsccOutputData, error) { - return v.CIns, &sysccprovider.VsccOutputData{ProposalResponseData: [][]byte{v.RespPayl}}, nil +func (v *MockVsccValidator) VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) { + return nil, peer.TxValidationCode_VALID } diff --git a/core/peer/peer_test.go b/core/peer/peer_test.go index d3da64b4567..29d5262805d 100644 --- a/core/peer/peer_test.go +++ b/core/peer/peer_test.go @@ -24,7 +24,9 @@ import ( configtxtest "github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/common/localmsp" + mscc "github.com/hyperledger/fabric/common/mocks/scc" ccp "github.com/hyperledger/fabric/core/common/ccprovider" + "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/deliverservice" "github.com/hyperledger/fabric/core/deliverservice/blocksprovider" "github.com/hyperledger/fabric/core/mocks/ccprovider" @@ -71,6 +73,7 @@ func TestInitialize(t *testing.T) { // we mock this because we can't import the chaincode package lest we create an import cycle ccp.RegisterChaincodeProviderFactory(&ccprovider.MockCcProviderFactory{}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&mscc.MocksccProviderFactory{}) Initialize(nil) } diff --git a/core/scc/cscc/configure_test.go b/core/scc/cscc/configure_test.go index fad5b0a5b92..f8c8c512503 100644 --- a/core/scc/cscc/configure_test.go +++ b/core/scc/cscc/configure_test.go @@ -25,9 +25,11 @@ import ( "github.com/golang/protobuf/proto" configtxtest "github.com/hyperledger/fabric/common/configtx/test" "github.com/hyperledger/fabric/common/localmsp" + "github.com/hyperledger/fabric/common/mocks/scc" "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/chaincode" "github.com/hyperledger/fabric/core/chaincode/shim" + "github.com/hyperledger/fabric/core/common/sysccprovider" "github.com/hyperledger/fabric/core/deliverservice" "github.com/hyperledger/fabric/core/deliverservice/blocksprovider" "github.com/hyperledger/fabric/core/ledger/ledgermgmt" @@ -130,6 +132,8 @@ func TestConfigerInvokeJoinChainWrongParams(t *testing.T) { } func TestConfigerInvokeJoinChainCorrectParams(t *testing.T) { + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{}) + viper.Set("peer.fileSystemPath", "/tmp/hyperledgertest/") viper.Set("chaincode.executetimeout", "3000") os.Mkdir("/tmp/hyperledgertest", 0755) diff --git a/core/scc/importsysccs.go b/core/scc/importsysccs.go index c1e45cdb529..1df323e83b2 100644 --- a/core/scc/importsysccs.go +++ b/core/scc/importsysccs.go @@ -105,10 +105,10 @@ func IsSysCC(name string) bool { return false } -// IsSysCCAndNotInvokable returns true if the chaincode +// IsSysCCAndNotInvokableExternal returns true if the chaincode // is a system chaincode and *CANNOT* be invoked through // a proposal to this peer -func IsSysCCAndNotInvokable(name string) bool { +func IsSysCCAndNotInvokableExternal(name string) bool { for _, sysCC := range systemChaincodes { if sysCC.Name == name { return !sysCC.InvokableExternal diff --git a/core/scc/lscc/lscc_test.go b/core/scc/lscc/lscc_test.go index 1772cdf362d..e4982966d50 100644 --- a/core/scc/lscc/lscc_test.go +++ b/core/scc/lscc/lscc_test.go @@ -34,6 +34,7 @@ import ( "bytes" "compress/gzip" + "github.com/hyperledger/fabric/common/mocks/scc" "github.com/hyperledger/fabric/common/policies" "github.com/hyperledger/fabric/core/policy" "github.com/hyperledger/fabric/msp" @@ -43,43 +44,12 @@ 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" ) var lscctestpath = "/tmp/lscctest" -type mocksccProviderFactory struct { -} - -func (c *mocksccProviderFactory) NewSystemChaincodeProvider() sysccprovider.SystemChaincodeProvider { - return &mocksccProviderImpl{} -} - -type mocksccProviderImpl struct { -} - -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 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 { - return fmt.Errorf(string(res.Message)) - } - return nil -} - func constructDeploymentSpec(name string, path string, version string, initArgs [][]byte, createFS bool) (*pb.ChaincodeDeploymentSpec, error) { spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: name, Path: path, Version: version}, Input: &pb.ChaincodeInput{Args: initArgs}} @@ -1244,7 +1214,8 @@ var chainid string = util.GetTestChainID() func TestMain(m *testing.M) { ccprovider.SetChaincodesPath(lscctestpath) - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{}) + var err error // setup the MSP manager so that we can sign/verify diff --git a/core/scc/sccproviderimpl.go b/core/scc/sccproviderimpl.go index e36ab4c3c65..53b2c7d328f 100644 --- a/core/scc/sccproviderimpl.go +++ b/core/scc/sccproviderimpl.go @@ -55,6 +55,7 @@ func (c *sccProviderImpl) IsSysCCAndNotInvokableCC2CC(name string) bool { return IsSysCCAndNotInvokableCC2CC(name) } +// GetQueryExecutorForLedger returns a query executor for the specified channel func (c *sccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExecutor, error) { l := peer.GetLedger(cid) if l == nil { @@ -63,3 +64,10 @@ func (c *sccProviderImpl) GetQueryExecutorForLedger(cid string) (ledger.QueryExe return l.NewQueryExecutor() } + +// IsSysCCAndNotInvokableExternal returns true if the supplied chaincode is +// ia system chaincode and it NOT nvokable +func (c *sccProviderImpl) IsSysCCAndNotInvokableExternal(name string) bool { + // call the static method of the same name + return IsSysCCAndNotInvokableExternal(name) +} diff --git a/core/scc/vscc/validator_onevalidsignature.go b/core/scc/vscc/validator_onevalidsignature.go index 546c7291fb4..2ac3661dd19 100644 --- a/core/scc/vscc/validator_onevalidsignature.go +++ b/core/scc/vscc/validator_onevalidsignature.go @@ -126,7 +126,6 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) return shim.Error(err.Error()) } - prespBytesData := [][]byte{} // loop through each of the actions within for _, act := range tx.Actions { cap, err := utils.GetChaincodeActionPayload(act.Payload) @@ -175,21 +174,11 @@ func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) return shim.Error(err.Error()) } } - - prespBytesData = append(prespBytesData, prespBytes) - } - - vsccOutputData := &sysccprovider.VsccOutputData{ - ProposalResponseData: prespBytesData, - } - vodBytes, err := utils.Marshal(vsccOutputData) - if err != nil { - return shim.Error(err.Error()) } logger.Debugf("VSCC exists successfully") - return shim.Success(vodBytes) + return shim.Success(nil) } // checkInstantiationPolicy evaluates an instantiation policy against a signed proposal diff --git a/core/scc/vscc/validator_onevalidsignature_test.go b/core/scc/vscc/validator_onevalidsignature_test.go index ab1071c080a..90c90a97029 100644 --- a/core/scc/vscc/validator_onevalidsignature_test.go +++ b/core/scc/vscc/validator_onevalidsignature_test.go @@ -18,23 +18,24 @@ package vscc import ( "testing" - "bytes" "fmt" "os" "archive/tar" "compress/gzip" + "bytes" + "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/common/cauthdsl" lm "github.com/hyperledger/fabric/common/mocks/ledger" + "github.com/hyperledger/fabric/common/mocks/scc" "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" @@ -211,7 +212,7 @@ func TestInvoke(t *testing.T) { t.Fatalf("vscc invoke should have failed") } - tx, presp, err := createTx() + tx, _, err := createTx() if err != nil { t.Fatalf("createTx returned err %s", err) } @@ -221,15 +222,6 @@ func TestInvoke(t *testing.T) { t.Fatalf("GetBytesEnvelope returned err %s", err) } - expectVod := &sysccprovider.VsccOutputData{ - ProposalResponseData: [][]byte{presp.Payload}, - } - expectVodBytes, err := utils.Marshal(expectVod) - if err != nil { - t.Fatalf("Marshal VsccOutputData failed, err %s", err) - return - } - // good path: signed by the right MSP policy, err := getSignedByMSPMemberPolicy(mspid) if err != nil { @@ -242,11 +234,6 @@ func TestInvoke(t *testing.T) { t.Fatalf("vscc invoke returned err %s", err) } - if bytes.Compare(expectVodBytes, res.Payload) != 0 { - t.Fatalf("vscc returned error payload") - return - } - // bad path: signed by the wrong MSP policy, err = getSignedByMSPMemberPolicy("barf") if err != nil { @@ -268,7 +255,7 @@ func TestInvalidFunction(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -320,7 +307,7 @@ func TestRWSetTooBig(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -384,7 +371,7 @@ func TestValidateDeployFail(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -588,7 +575,7 @@ func TestAlreadyDeployed(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -662,7 +649,7 @@ func TestValidateDeployOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -714,7 +701,7 @@ func TestValidateDeployWithPolicies(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -798,7 +785,7 @@ func TestInvalidUpgrade(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -850,7 +837,7 @@ func TestValidateUpgradeOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -926,7 +913,7 @@ func TestInvalidateUpgradeBadVersion(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1000,7 +987,7 @@ func TestValidateUpgradeWithPoliciesOK(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1078,7 +1065,7 @@ func TestValidateUpgradeWithPoliciesFail(t *testing.T) { State := make(map[string]map[string][]byte) State["lscc"] = stublccc.State - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{Qe: lm.NewMockQueryExecutor(State)}) stub.MockPeerChaincode("lscc", stublccc) r1 := stub.MockInit("1", [][]byte{}) @@ -1153,30 +1140,6 @@ 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 { } @@ -1203,7 +1166,7 @@ var lccctestpath = "/tmp/lscc-validation-test" func TestMain(m *testing.M) { ccprovider.SetChaincodesPath(lccctestpath) - sysccprovider.RegisterSystemChaincodeProviderFactory(&mocksccProviderFactory{}) + sysccprovider.RegisterSystemChaincodeProviderFactory(&scc.MocksccProviderFactory{}) policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{}) var err error diff --git a/protos/peer/transaction.pb.go b/protos/peer/transaction.pb.go index 3238c912cba..2a486db25d2 100644 --- a/protos/peer/transaction.pb.go +++ b/protos/peer/transaction.pb.go @@ -37,6 +37,11 @@ const ( TxValidationCode_NIL_TXACTION TxValidationCode = 16 TxValidationCode_EXPIRED_CHAINCODE TxValidationCode = 17 TxValidationCode_CHAINCODE_VERSION_CONFLICT TxValidationCode = 18 + TxValidationCode_BAD_HEADER_EXTENSION TxValidationCode = 19 + TxValidationCode_BAD_CHANNEL_HEADER TxValidationCode = 20 + TxValidationCode_BAD_RESPONSE_PAYLOAD TxValidationCode = 21 + TxValidationCode_BAD_RWSET TxValidationCode = 22 + TxValidationCode_ILLEGAL_WRITESET TxValidationCode = 23 TxValidationCode_INVALID_OTHER_REASON TxValidationCode = 255 ) @@ -60,6 +65,11 @@ var TxValidationCode_name = map[int32]string{ 16: "NIL_TXACTION", 17: "EXPIRED_CHAINCODE", 18: "CHAINCODE_VERSION_CONFLICT", + 19: "BAD_HEADER_EXTENSION", + 20: "BAD_CHANNEL_HEADER", + 21: "BAD_RESPONSE_PAYLOAD", + 22: "BAD_RWSET", + 23: "ILLEGAL_WRITESET", 255: "INVALID_OTHER_REASON", } var TxValidationCode_value = map[string]int32{ @@ -82,6 +92,11 @@ var TxValidationCode_value = map[string]int32{ "NIL_TXACTION": 16, "EXPIRED_CHAINCODE": 17, "CHAINCODE_VERSION_CONFLICT": 18, + "BAD_HEADER_EXTENSION": 19, + "BAD_CHANNEL_HEADER": 20, + "BAD_RESPONSE_PAYLOAD": 21, + "BAD_RWSET": 22, + "ILLEGAL_WRITESET": 23, "INVALID_OTHER_REASON": 255, } @@ -245,54 +260,58 @@ func init() { func init() { proto.RegisterFile("peer/transaction.proto", fileDescriptor11) } var fileDescriptor11 = []byte{ - // 772 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x54, 0x41, 0x6f, 0xe3, 0x44, - 0x18, 0x25, 0x2d, 0x6d, 0xe9, 0x97, 0xd2, 0x4e, 0xa6, 0xdd, 0x6c, 0x1a, 0x55, 0xec, 0x2a, 0x07, - 0xb4, 0x80, 0x94, 0x48, 0xdd, 0x03, 0x12, 0xe2, 0x32, 0xb1, 0xa7, 0x8d, 0x85, 0x33, 0x63, 0x8d, - 0x27, 0xa1, 0xe5, 0xc0, 0xc8, 0x89, 0x67, 0xd3, 0x88, 0xc4, 0xb6, 0x6c, 0x77, 0x45, 0xaf, 0xfc, - 0x00, 0xf8, 0xbd, 0x9c, 0x40, 0xf6, 0xd8, 0x49, 0xda, 0x85, 0x4b, 0x9c, 0x79, 0xef, 0xcd, 0xf7, - 0xde, 0xf7, 0x79, 0x3c, 0xd0, 0x4e, 0xb4, 0x4e, 0x07, 0x79, 0x1a, 0x44, 0x59, 0x30, 0xcf, 0x97, - 0x71, 0xd4, 0x4f, 0xd2, 0x38, 0x8f, 0xf1, 0x61, 0xf9, 0xc8, 0xba, 0x6f, 0x16, 0x71, 0xbc, 0x58, - 0xe9, 0x41, 0xb9, 0x9c, 0x3d, 0x7e, 0x18, 0xe4, 0xcb, 0xb5, 0xce, 0xf2, 0x60, 0x9d, 0x18, 0x61, - 0xf7, 0xaa, 0x2c, 0x90, 0xa4, 0x71, 0x12, 0x67, 0xc1, 0x4a, 0xa5, 0x3a, 0x4b, 0xe2, 0x28, 0xd3, - 0x15, 0x7b, 0x3e, 0x8f, 0xd7, 0xeb, 0x38, 0x1a, 0x98, 0x87, 0x01, 0x7b, 0xbf, 0x42, 0xcb, 0x5f, - 0x2e, 0x22, 0x1d, 0xca, 0xad, 0x2d, 0xfe, 0x0e, 0x5a, 0x3b, 0x29, 0xd4, 0xec, 0x29, 0xd7, 0x59, - 0xa7, 0xf1, 0xb6, 0xf1, 0xee, 0x44, 0xa0, 0x1d, 0x62, 0x58, 0xe0, 0xf8, 0x0a, 0x8e, 0xb3, 0xe5, - 0x22, 0x0a, 0xf2, 0xc7, 0x54, 0x77, 0xf6, 0x4a, 0xd1, 0x16, 0xe8, 0xfd, 0xd1, 0x80, 0x0b, 0x2f, - 0x8d, 0xe7, 0x3a, 0xcb, 0x9e, 0x7b, 0x0c, 0xe1, 0x7c, 0xa7, 0x14, 0x8d, 0x3e, 0xea, 0x55, 0x9c, - 0xe8, 0xd2, 0xa5, 0x79, 0x8d, 0xfa, 0x55, 0xc8, 0x1a, 0x17, 0xff, 0x25, 0xc6, 0x5f, 0xc3, 0xe9, - 0xc7, 0x60, 0xb5, 0x0c, 0x83, 0x02, 0xb5, 0xe2, 0xd0, 0xf8, 0x1f, 0x88, 0x17, 0x68, 0x6f, 0x08, - 0xcd, 0x5d, 0xeb, 0xf7, 0x70, 0x64, 0xfe, 0x15, 0x4d, 0xed, 0xbf, 0x6b, 0x5e, 0x5f, 0x9a, 0x61, - 0x64, 0xfd, 0x1d, 0x15, 0x29, 0x7f, 0x45, 0xad, 0xec, 0x51, 0x68, 0x7d, 0xc2, 0xe2, 0x36, 0x1c, - 0x3e, 0xe8, 0x20, 0xd4, 0x69, 0x35, 0x9d, 0x6a, 0x85, 0x3b, 0x70, 0x94, 0x04, 0x4f, 0xab, 0x38, - 0x08, 0xab, 0x89, 0xd4, 0xcb, 0xde, 0x5f, 0x0d, 0x68, 0x5b, 0x0f, 0xc1, 0x32, 0x9a, 0xc7, 0xa1, - 0x36, 0x55, 0x3c, 0x43, 0xe1, 0x1f, 0xa1, 0x3b, 0xaf, 0x19, 0xb5, 0x79, 0x89, 0x75, 0x1d, 0x63, - 0xd0, 0xd9, 0x28, 0xbc, 0x4a, 0x50, 0xef, 0xfe, 0x1e, 0x0e, 0x4d, 0xb4, 0xd2, 0xb1, 0x79, 0xfd, - 0xa6, 0xee, 0x69, 0xe3, 0x46, 0xa3, 0x30, 0x4e, 0x33, 0x1d, 0x56, 0x9d, 0x55, 0xf2, 0xde, 0x9f, - 0x0d, 0x78, 0xfd, 0x3f, 0x1a, 0xfc, 0x03, 0x5c, 0x7e, 0x72, 0x9a, 0x5e, 0x24, 0x7a, 0x5d, 0x0b, - 0x44, 0xc5, 0x6f, 0x03, 0x9d, 0x68, 0x53, 0x6d, 0xad, 0xa3, 0x3c, 0xeb, 0xec, 0x95, 0xa3, 0x3e, - 0xaf, 0x63, 0xd1, 0x2d, 0x27, 0x9e, 0x09, 0xbf, 0xfd, 0x7b, 0x1f, 0x90, 0xfc, 0x7d, 0xfa, 0xec, - 0x15, 0xe2, 0x63, 0x38, 0x98, 0x12, 0xd7, 0xb1, 0xd1, 0x67, 0x18, 0xc1, 0x09, 0x73, 0x5c, 0x45, - 0xd9, 0x94, 0xba, 0xdc, 0xa3, 0xa8, 0x81, 0xcf, 0xa0, 0x39, 0x24, 0xb6, 0xf2, 0xc8, 0xbd, 0xcb, - 0x89, 0x8d, 0xf6, 0xf0, 0x2b, 0x68, 0x15, 0x80, 0xc5, 0xc7, 0x63, 0xce, 0xd4, 0x88, 0x12, 0x9b, - 0x0a, 0xb4, 0x8f, 0x2f, 0xe1, 0x55, 0x09, 0x0b, 0x4a, 0x24, 0x17, 0xca, 0x77, 0x6e, 0x19, 0x91, - 0x13, 0x41, 0xd1, 0xe7, 0xf8, 0x2d, 0x5c, 0x39, 0xac, 0x74, 0x50, 0x94, 0xd9, 0x5c, 0xf8, 0x54, - 0x28, 0x29, 0x08, 0xf3, 0x89, 0x25, 0x1d, 0xce, 0xd0, 0x01, 0xfe, 0x0a, 0xba, 0xb5, 0xc2, 0xe2, - 0xec, 0xc6, 0xb9, 0x7d, 0xc6, 0x1f, 0xe2, 0x2e, 0xb4, 0x27, 0xcc, 0x9f, 0x78, 0x1e, 0x17, 0x92, - 0xda, 0x4a, 0xde, 0x6d, 0xf2, 0x1c, 0xd5, 0x79, 0x3c, 0xc1, 0x3d, 0xee, 0x13, 0x57, 0xc9, 0x3b, - 0xc7, 0x46, 0x5f, 0x60, 0x0c, 0xa7, 0xf6, 0xc4, 0x73, 0x1d, 0x8b, 0x48, 0x6a, 0xb0, 0xe3, 0xc2, - 0xa6, 0x0a, 0x30, 0xa6, 0x4c, 0x2a, 0x8f, 0xbb, 0x8e, 0x75, 0xaf, 0x6e, 0x88, 0xe3, 0x16, 0x41, - 0x01, 0xb7, 0x01, 0x8f, 0xa7, 0x96, 0xa5, 0x04, 0x25, 0x26, 0x88, 0xeb, 0x58, 0x12, 0x35, 0x8b, - 0xde, 0xbc, 0x11, 0x61, 0x92, 0x8f, 0x5f, 0x50, 0x27, 0xf8, 0x1c, 0xce, 0x26, 0xec, 0x27, 0xc6, - 0x7f, 0x66, 0x45, 0x2a, 0x79, 0xef, 0x51, 0xf4, 0x65, 0x11, 0x57, 0x12, 0x71, 0x4b, 0xa5, 0xb2, - 0x46, 0xc4, 0x61, 0x8a, 0x71, 0xa9, 0x6e, 0xf8, 0x84, 0xd9, 0xe8, 0x14, 0x5f, 0x00, 0x1a, 0x13, - 0xe1, 0x8f, 0xca, 0xa4, 0x8a, 0x0a, 0xc1, 0x05, 0x3a, 0xab, 0xe7, 0x2e, 0xef, 0xaa, 0x96, 0x51, - 0xd1, 0x16, 0xbd, 0xf3, 0x1c, 0x41, 0x6d, 0x53, 0xc4, 0xe2, 0x36, 0x45, 0xad, 0xa2, 0x85, 0xcd, - 0x52, 0x4d, 0xa9, 0xf0, 0x1d, 0xce, 0xb6, 0x79, 0x30, 0xbe, 0x84, 0x8b, 0x7a, 0x92, 0x5c, 0x8e, - 0xa8, 0x28, 0x02, 0xfb, 0x9c, 0xa1, 0x7f, 0x1a, 0xc3, 0x39, 0xf4, 0xe2, 0x74, 0xd1, 0x7f, 0x78, - 0x4a, 0x74, 0xba, 0xd2, 0xe1, 0x42, 0xa7, 0xfd, 0x0f, 0xc1, 0x2c, 0x5d, 0xce, 0xeb, 0x63, 0x53, - 0xdc, 0x70, 0x43, 0xbc, 0xf3, 0x25, 0x7a, 0xc1, 0xfc, 0xb7, 0x60, 0xa1, 0x7f, 0xf9, 0x66, 0xb1, - 0xcc, 0x1f, 0x1e, 0x67, 0xc5, 0xc5, 0x31, 0xd8, 0xd9, 0x3e, 0x30, 0xdb, 0xcd, 0x9d, 0x99, 0x0d, - 0x8a, 0xed, 0x33, 0x73, 0x9f, 0xbe, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x5b, 0x0c, 0x7d, - 0x70, 0x05, 0x00, 0x00, + // 833 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x54, 0xd1, 0x6e, 0xe2, 0x46, + 0x14, 0x2d, 0xd9, 0x4d, 0xd2, 0x0c, 0xd9, 0x64, 0x32, 0x10, 0x42, 0x50, 0xd4, 0x5d, 0xf1, 0x50, + 0x6d, 0x5b, 0x09, 0xa4, 0xec, 0x43, 0xa5, 0xaa, 0x2f, 0x83, 0x3d, 0x09, 0x56, 0xcd, 0x8c, 0x35, + 0x1e, 0x08, 0xe9, 0x43, 0x47, 0x06, 0xcf, 0x12, 0x54, 0xb0, 0x2d, 0xdb, 0x59, 0x35, 0xaf, 0xfd, + 0x80, 0xf6, 0x3f, 0xfb, 0x13, 0xad, 0xc6, 0x63, 0x03, 0xc9, 0x76, 0x5f, 0x30, 0x73, 0xcf, 0xb9, + 0xf7, 0x9c, 0x7b, 0xaf, 0x3d, 0xa0, 0x95, 0x28, 0x95, 0xf6, 0xf3, 0x34, 0x88, 0xb2, 0x60, 0x9e, + 0x2f, 0xe3, 0xa8, 0x97, 0xa4, 0x71, 0x1e, 0xa3, 0x83, 0xe2, 0x91, 0x75, 0xde, 0x2e, 0xe2, 0x78, + 0xb1, 0x52, 0xfd, 0xe2, 0x38, 0x7b, 0xfc, 0xd8, 0xcf, 0x97, 0x6b, 0x95, 0xe5, 0xc1, 0x3a, 0x31, + 0xc4, 0xce, 0x55, 0x51, 0x20, 0x49, 0xe3, 0x24, 0xce, 0x82, 0x95, 0x4c, 0x55, 0x96, 0xc4, 0x51, + 0xa6, 0x4a, 0xb4, 0x31, 0x8f, 0xd7, 0xeb, 0x38, 0xea, 0x9b, 0x87, 0x09, 0x76, 0x7f, 0x03, 0x67, + 0xfe, 0x72, 0x11, 0xa9, 0x50, 0x6c, 0x65, 0xd1, 0x0f, 0xe0, 0x6c, 0xc7, 0x85, 0x9c, 0x3d, 0xe5, + 0x2a, 0x6b, 0xd7, 0xde, 0xd5, 0xde, 0x1f, 0x73, 0xb8, 0x03, 0x0c, 0x74, 0x1c, 0x5d, 0x81, 0xa3, + 0x6c, 0xb9, 0x88, 0x82, 0xfc, 0x31, 0x55, 0xed, 0xbd, 0x82, 0xb4, 0x0d, 0x74, 0xff, 0xac, 0x81, + 0xa6, 0x97, 0xc6, 0x73, 0x95, 0x65, 0xcf, 0x35, 0x06, 0xa0, 0xb1, 0x53, 0x8a, 0x44, 0x9f, 0xd4, + 0x2a, 0x4e, 0x54, 0xa1, 0x52, 0xbf, 0x86, 0xbd, 0xd2, 0x64, 0x15, 0xe7, 0xff, 0x47, 0x46, 0xdf, + 0x82, 0x93, 0x4f, 0xc1, 0x6a, 0x19, 0x06, 0x3a, 0x6a, 0xc5, 0xa1, 0xd1, 0xdf, 0xe7, 0x2f, 0xa2, + 0xdd, 0x01, 0xa8, 0xef, 0x4a, 0x7f, 0x00, 0x87, 0xe6, 0x9f, 0x6e, 0xea, 0xd5, 0xfb, 0xfa, 0xf5, + 0xa5, 0x19, 0x46, 0xd6, 0xdb, 0x61, 0xe1, 0xe2, 0x97, 0x57, 0xcc, 0x2e, 0x01, 0x67, 0x9f, 0xa1, + 0xa8, 0x05, 0x0e, 0x1e, 0x54, 0x10, 0xaa, 0xb4, 0x9c, 0x4e, 0x79, 0x42, 0x6d, 0x70, 0x98, 0x04, + 0x4f, 0xab, 0x38, 0x08, 0xcb, 0x89, 0x54, 0xc7, 0xee, 0xdf, 0x35, 0xd0, 0xb2, 0x1e, 0x82, 0x65, + 0x34, 0x8f, 0x43, 0x65, 0xaa, 0x78, 0x06, 0x42, 0x3f, 0x83, 0xce, 0xbc, 0x42, 0xe4, 0x66, 0x89, + 0x55, 0x1d, 0x23, 0xd0, 0xde, 0x30, 0xbc, 0x92, 0x50, 0x65, 0xff, 0x08, 0x0e, 0x8c, 0xb5, 0x42, + 0xb1, 0x7e, 0xfd, 0xb6, 0xea, 0x69, 0xa3, 0x46, 0xa2, 0x30, 0x4e, 0x33, 0x15, 0x96, 0x9d, 0x95, + 0xf4, 0xee, 0x5f, 0x35, 0x70, 0xf1, 0x05, 0x0e, 0xfa, 0x09, 0x5c, 0x7e, 0xf6, 0x36, 0xbd, 0x70, + 0x74, 0x51, 0x11, 0x78, 0x89, 0x6f, 0x0d, 0x1d, 0x2b, 0x53, 0x6d, 0xad, 0xa2, 0x3c, 0x6b, 0xef, + 0x15, 0xa3, 0x6e, 0x54, 0xb6, 0xc8, 0x16, 0xe3, 0xcf, 0x88, 0xdf, 0xff, 0xf3, 0x1a, 0x40, 0xf1, + 0xc7, 0xe4, 0xd9, 0x0a, 0xd1, 0x11, 0xd8, 0x9f, 0x60, 0xd7, 0xb1, 0xe1, 0x57, 0x08, 0x82, 0x63, + 0xea, 0xb8, 0x92, 0xd0, 0x09, 0x71, 0x99, 0x47, 0x60, 0x0d, 0x9d, 0x82, 0xfa, 0x00, 0xdb, 0xd2, + 0xc3, 0xf7, 0x2e, 0xc3, 0x36, 0xdc, 0x43, 0xe7, 0xe0, 0x4c, 0x07, 0x2c, 0x36, 0x1a, 0x31, 0x2a, + 0x87, 0x04, 0xdb, 0x84, 0xc3, 0x57, 0xe8, 0x12, 0x9c, 0x17, 0x61, 0x4e, 0xb0, 0x60, 0x5c, 0xfa, + 0xce, 0x2d, 0xc5, 0x62, 0xcc, 0x09, 0x7c, 0x8d, 0xde, 0x81, 0x2b, 0x87, 0x16, 0x0a, 0x92, 0x50, + 0x9b, 0x71, 0x9f, 0x70, 0x29, 0x38, 0xa6, 0x3e, 0xb6, 0x84, 0xc3, 0x28, 0xdc, 0x47, 0xdf, 0x80, + 0x4e, 0xc5, 0xb0, 0x18, 0xbd, 0x71, 0x6e, 0x9f, 0xe1, 0x07, 0xa8, 0x03, 0x5a, 0x63, 0xea, 0x8f, + 0x3d, 0x8f, 0x71, 0x41, 0x6c, 0x29, 0xa6, 0x1b, 0x3f, 0x87, 0x95, 0x1f, 0x8f, 0x33, 0x8f, 0xf9, + 0xd8, 0x95, 0x62, 0xea, 0xd8, 0xf0, 0x6b, 0x84, 0xc0, 0x89, 0x3d, 0xf6, 0x5c, 0xc7, 0xc2, 0x82, + 0x98, 0xd8, 0x91, 0x96, 0x29, 0x0d, 0x8c, 0x08, 0x15, 0xd2, 0x63, 0xae, 0x63, 0xdd, 0xcb, 0x1b, + 0xec, 0xb8, 0xda, 0x28, 0x40, 0x2d, 0x80, 0x46, 0x13, 0xcb, 0x92, 0x9c, 0x60, 0x63, 0xc4, 0x75, + 0x2c, 0x01, 0xeb, 0xba, 0x37, 0x6f, 0x88, 0xa9, 0x60, 0xa3, 0x17, 0xd0, 0x31, 0x6a, 0x80, 0xd3, + 0x31, 0xfd, 0x85, 0xb2, 0x3b, 0xaa, 0x5d, 0x89, 0x7b, 0x8f, 0xc0, 0x37, 0xda, 0xae, 0xc0, 0xfc, + 0x96, 0x08, 0x69, 0x0d, 0xb1, 0x43, 0x25, 0x65, 0x42, 0xde, 0xb0, 0x31, 0xb5, 0xe1, 0x09, 0x6a, + 0x02, 0x38, 0xc2, 0xdc, 0x1f, 0x16, 0x4e, 0x25, 0xe1, 0x9c, 0x71, 0x78, 0x5a, 0xcd, 0x5d, 0x4c, + 0xcb, 0x96, 0xa1, 0x6e, 0x8b, 0x4c, 0x3d, 0x87, 0x13, 0xdb, 0x14, 0xb1, 0x98, 0x4d, 0xe0, 0x99, + 0x6e, 0x61, 0x73, 0x94, 0x13, 0xc2, 0x7d, 0x87, 0xd1, 0xad, 0x1f, 0x84, 0xda, 0xa0, 0xa9, 0xa7, + 0x61, 0xd6, 0x22, 0xc9, 0x54, 0x10, 0xaa, 0x29, 0xb0, 0xa1, 0x9b, 0x2b, 0x16, 0x34, 0xc4, 0x94, + 0x12, 0xb7, 0x5a, 0x5c, 0xb3, 0xca, 0xe0, 0xc4, 0xf7, 0x18, 0xf5, 0xc9, 0x66, 0xb2, 0xe7, 0xe8, + 0x0d, 0x38, 0x2a, 0x90, 0x3b, 0x9f, 0x08, 0xd8, 0xd2, 0xce, 0x1d, 0xd7, 0x25, 0xb7, 0xd8, 0x95, + 0x77, 0xdc, 0x11, 0x44, 0x47, 0x2f, 0xd0, 0x25, 0x68, 0x56, 0xab, 0x63, 0x62, 0x48, 0xb8, 0x9e, + 0x90, 0xcf, 0x28, 0xfc, 0xb7, 0x36, 0x98, 0x83, 0x6e, 0x9c, 0x2e, 0x7a, 0x0f, 0x4f, 0x89, 0x4a, + 0x57, 0x2a, 0x5c, 0xa8, 0xb4, 0xf7, 0x31, 0x98, 0xa5, 0xcb, 0x79, 0xf5, 0x9e, 0xea, 0x2b, 0x75, + 0x80, 0x76, 0x3e, 0x7d, 0x2f, 0x98, 0xff, 0x1e, 0x2c, 0xd4, 0xaf, 0xdf, 0x2d, 0x96, 0xf9, 0xc3, + 0xe3, 0x4c, 0xdf, 0x54, 0xfd, 0x9d, 0xf4, 0xbe, 0x49, 0x37, 0x97, 0x74, 0xd6, 0xd7, 0xe9, 0x33, + 0x73, 0x81, 0x7f, 0xf8, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x19, 0x1c, 0xb2, 0xe4, 0xe1, 0x05, 0x00, + 0x00, } diff --git a/protos/peer/transaction.proto b/protos/peer/transaction.proto index 39721b3126f..bb18cf3152c 100644 --- a/protos/peer/transaction.proto +++ b/protos/peer/transaction.proto @@ -142,5 +142,10 @@ enum TxValidationCode { NIL_TXACTION = 16; EXPIRED_CHAINCODE = 17; CHAINCODE_VERSION_CONFLICT = 18; + BAD_HEADER_EXTENSION = 19; + BAD_CHANNEL_HEADER = 20; + BAD_RESPONSE_PAYLOAD = 21; + BAD_RWSET = 22; + ILLEGAL_WRITESET = 23; INVALID_OTHER_REASON = 255; } diff --git a/protos/utils/proputils.go b/protos/utils/proputils.go index 4795b7a8c38..5af105dddb5 100644 --- a/protos/utils/proputils.go +++ b/protos/utils/proputils.go @@ -381,26 +381,6 @@ func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.He return &peer.Proposal{Header: hdrBytes, Payload: ccPropPayloadBytes}, txid, nil } -// GetChaincodeIDFromBytesProposalResponsePayload gets ChaincodeID from given ProposalResponsePayload bytes. -// Only proposalresponse bytes from ENDORSER_TRANSACTION should be passed in (we don't have info to check that). -func GetChaincodeIDFromBytesProposalResponsePayload(prpBytes []byte) (*peer.ChaincodeID, error) { - prp, err := GetProposalResponsePayload(prpBytes) - if err != nil { - return nil, err - } - - cact, err := GetChaincodeAction(prp.Extension) - if err != nil { - return nil, err - } - - if cact.ChaincodeId == nil { - return nil, fmt.Errorf("Empty ChaincodeID") - } - - return cact.ChaincodeId, nil -} - // GetBytesProposalResponsePayload gets proposal response payload func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) { cAct := &peer.ChaincodeAction{Events: event, Results: result, Response: response, ChaincodeId: ccid}