Skip to content

Commit

Permalink
[FAB-187] VSCC uses policies specified upon deploy
Browse files Browse the repository at this point in the history
This change-set provides support for endorsement policies. At chaincode deploy
time, the deployer can specify the endorsement policy it requires from command
line. The cc deploy tx is sent to lccc which stores the policy. Later, the
validator can extract the policy and send it to VSCC.

Change-Id: Ic1bc0e492a9070a355cfba83dfa56d121902c543
Signed-off-by: Alessandro Sorniotti <ale.linux@sopit.net>
  • Loading branch information
ale-linux committed Jan 30, 2017
1 parent 6255f8d commit b7fd939
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 102 deletions.
17 changes: 12 additions & 5 deletions core/chaincode/ccproviderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package chaincode
import (
"context"

"fmt"

"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/ledger"
pb "github.com/hyperledger/fabric/protos/peer"
Expand Down Expand Up @@ -72,18 +74,23 @@ func (c *ccProviderImpl) GetCCContext(cid, name, version, txid string, syscc boo

// GetCCValidationInfoFromLCCC returns the VSCC and the policy listed in LCCC for the supplied chaincode
func (c *ccProviderImpl) GetCCValidationInfoFromLCCC(ctxt context.Context, txid string, prop *pb.Proposal, chainID string, chaincodeID string) (string, []byte, error) {
// LCCC does not have any notion about its own
// endorsing policy - we should never call this
// function with lccc as the chaincodeID
if chaincodeID == "lccc" {
panic("GetCCValidationInfoFromLCCC invoke for LCCC")
}

data, err := GetChaincodeDataFromLCCC(ctxt, txid, prop, chainID, chaincodeID)
if err != nil {
return "", nil, err
}

vscc := "vscc"
// Check whenever VSCC defined for chaincode data
if data != nil && data.Vscc != "" {
vscc = data.Vscc
if data == nil || data.Vscc == "" || data.Policy == nil {
return "", nil, fmt.Errorf("Incorrect validation info in LCCC")
}

return vscc, data.Policy, nil
return data.Vscc, data.Policy, nil
}

// ExecuteChaincode executes the chaincode specified in the context with the specified arguments
Expand Down
2 changes: 1 addition & 1 deletion core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func endTxSimulationCDS(chainID string, txid string, txsim ledger.TxSimulator, p
return err
}
// get a proposal - we need it to get a transaction
prop, err := putils.CreateDeployProposalFromCDS(txid, chainID, cds, ss)
prop, err := putils.CreateDeployProposalFromCDS(txid, chainID, cds, ss, nil, nil, nil)
if err != nil {
return err
}
Expand Down
89 changes: 24 additions & 65 deletions core/committer/txvalidator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@ import (
"fmt"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/common/cauthdsl"
coreUtil "github.com/hyperledger/fabric/common/util"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/core/common/ccprovider"
"github.com/hyperledger/fabric/core/common/validation"
"github.com/hyperledger/fabric/core/ledger"
ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/msp"

"github.com/hyperledger/fabric/protos/common"
"github.com/hyperledger/fabric/protos/utils"
"github.com/op/go-logging"
"github.com/syndtr/goleveldb/leveldb/errors"
)

// Support provides all of the needed to evaluate the VSCC
Expand Down Expand Up @@ -177,41 +176,6 @@ func (v *txValidator) Validate(block *common.Block) error {
return nil
}

// getSemiHardcodedPolicy returns a policy that requests
// one valid signature from the first MSP in this
// chain's MSP manager
// FIXME: this needs to be removed as soon as we extract the policy from LCCC
func getSemiHardcodedPolicy(chainID string, mspMgr msp.MSPManager) ([]byte, error) {
// 1) determine the MSP identifier for the first MSP in this chain
var msp msp.MSP
msps, err := mspMgr.GetMSPs()
if err != nil {
return nil, fmt.Errorf("Could not retrieve the MSPs for the chain manager, err %s", err)
}
if len(msps) == 0 {
return nil, errors.New("At least one MSP was expected")
}
for _, m := range msps {
msp = m
break
}
mspid, err := msp.GetIdentifier()
if err != nil {
return nil, fmt.Errorf("Failure getting the msp identifier, err %s", err)
}

// 2) get the policy
p := cauthdsl.SignedByMspMember(mspid)

// 3) marshal it and return it
b, err := proto.Marshal(p)
if err != nil {
return nil, fmt.Errorf("Could not marshal policy, err %s", err)
}

return b, err
}

func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte) error {
// Chain ID
chainID := payload.Header.ChainHeader.ChainID
Expand All @@ -230,21 +194,6 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
return err
}

// TODO: temporary workaround until the policy is specified
// by the deployer and can be retrieved via LCCC: we create
// a policy that requests 1 valid signature from this chain's
// MSP
policy, err := getSemiHardcodedPolicy(chainID, v.support.MSPManager())
if err != nil {
return 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}

ctxt, err := v.ccprovider.GetContext(v.support.Ledger())
if err != nil {
logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err)
Expand All @@ -258,22 +207,32 @@ func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []b
return err
}

// TODO: Temporary solution until FAB-1422 get resolved
// Explanation: we actually deploying chaincode transaction,
// hence no lccc yet to query for the data, therefore currently
// introducing a workaround to skip obtaining LCCC data.
vscc := "vscc"
if hdrExt.ChaincodeID.Name != "lccc" {
// Extracting vscc from lccc
// TODO: extract policy as well when available; it's the second argument returned by GetCCValidationInfoFromLCCC
vscc, _, err = v.ccprovider.GetCCValidationInfoFromLCCC(ctxt, txid, nil, chainID, hdrExt.ChaincodeID.Name)
if err != nil {
logger.Errorf("Unable to get chaincode data from LCCC for txid %s, due to %s", txid, err)
return err
}
// LCCC should not undergo standard VSCC type of
// validation. It should instead go through system
// policy validation to determine whether the issuer
// is entitled to deploy a chaincode on our chain
// VSCCValidateTx should
if hdrExt.ChaincodeID.Name == "lccc" {
// TODO: until FAB-1934 is in, we need to stop here
logger.Infof("Invocation of LCCC detected, no further VSCC validation necessary")
return nil
}

// obtain name of the VSCC and the policy from LCCC
vscc, policy, err := v.ccprovider.GetCCValidationInfoFromLCCC(ctxt, txid, nil, chainID, hdrExt.ChaincodeID.Name)
if err != nil {
logger.Errorf("Unable to get chaincode data from LCCC for txid %s, due to %s", txid, err)
return 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}

vscctxid := coreUtil.GenerateUUID()

// Get chaincode version
version := coreUtil.GetSysCCVersion()
cccid := v.ccprovider.GetCCContext(chainID, vscc, version, vscctxid, true, nil)
Expand Down
50 changes: 50 additions & 0 deletions core/common/sysccprovider/sysccprovider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
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 sysccprovider

// SystemChaincodeProvider provides an abstraction layer that is
// used for different packages to interact with code in the
// system chaincode package without importing it; more methods
// should be added below if necessary
type SystemChaincodeProvider interface {
// IsSysCC returns true if the supplied chaincode is a system chaincode
IsSysCC(name string) bool
}

var sccFactory SystemChaincodeProviderFactory

// SystemChaincodeProviderFactory defines a factory interface so
// that the actual implementation can be injected
type SystemChaincodeProviderFactory interface {
NewSystemChaincodeProvider() SystemChaincodeProvider
}

// RegisterSystemChaincodeProviderFactory is to be called once to set
// the factory that will be used to obtain instances of ChaincodeProvider
func RegisterSystemChaincodeProviderFactory(sccfact SystemChaincodeProviderFactory) {
sccFactory = sccfact
}

// GetSystemChaincodeProvider returns instances of SystemChaincodeProvider;
// the actual implementation is controlled by the factory that
// is registered via RegisterSystemChaincodeProviderFactory
func GetSystemChaincodeProvider() SystemChaincodeProvider {
if sccFactory == nil {
panic("The factory must be set first via RegisterSystemChaincodeProviderFactory")
}
return sccFactory.NewSystemChaincodeProvider()
}
2 changes: 1 addition & 1 deletion core/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, version s
//
//NOTE that if there's an error all simulation, including the chaincode
//table changes in lccc will be thrown away
if cid.Name == "lccc" && len(cis.ChaincodeSpec.Input.Args) == 3 && (string(cis.ChaincodeSpec.Input.Args[0]) == "deploy" || string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade") {
if cid.Name == "lccc" && len(cis.ChaincodeSpec.Input.Args) >= 3 && (string(cis.ChaincodeSpec.Input.Args[0]) == "deploy" || string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade") {
var ccVersion string
switch string(cis.ChaincodeSpec.Input.Args[0]) {
case "deploy":
Expand Down
12 changes: 12 additions & 0 deletions core/peer/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
"github.com/hyperledger/fabric/gossip/service"
"github.com/hyperledger/fabric/msp"
mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
"github.com/hyperledger/fabric/peer/sharedconfig"
"github.com/hyperledger/fabric/protos/common"
Expand Down Expand Up @@ -255,6 +256,17 @@ func GetLedger(cid string) ledger.PeerLedger {
return nil
}

// GetMSPMgr returns the MSP manager of the chain with chain ID.
// Note that this call returns nil if chain cid has not been created.
func GetMSPMgr(cid string) msp.MSPManager {
chains.RLock()
defer chains.RUnlock()
if c, ok := chains.list[cid]; ok {
return c.cs.MSPManager()
}
return nil
}

// GetCommitter returns the committer of the chain with chain ID. Note that this
// call returns nil if chain cid has not been created.
func GetCommitter(cid string) committer.Committer {
Expand Down
Loading

0 comments on commit b7fd939

Please sign in to comment.