github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/core/scc/vscc/validator_onevalidsignature.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package vscc
    18  
    19  import (
    20  	"fmt"
    21  
    22  	"github.com/golang/protobuf/proto"
    23  	"github.com/hyperledger/fabric/common/cauthdsl"
    24  	"github.com/hyperledger/fabric/common/flogging"
    25  	"github.com/hyperledger/fabric/core/chaincode/shim"
    26  	"github.com/hyperledger/fabric/core/scc/lscc"
    27  	mspmgmt "github.com/hyperledger/fabric/msp/mgmt"
    28  	"github.com/hyperledger/fabric/protos/common"
    29  	pb "github.com/hyperledger/fabric/protos/peer"
    30  	"github.com/hyperledger/fabric/protos/utils"
    31  )
    32  
    33  var logger = flogging.MustGetLogger("vscc")
    34  
    35  // ValidatorOneValidSignature implements the default transaction validation policy,
    36  // which is to check the correctness of the read-write set and the endorsement
    37  // signatures
    38  type ValidatorOneValidSignature struct {
    39  }
    40  
    41  // Init is called once when the chaincode started the first time
    42  func (vscc *ValidatorOneValidSignature) Init(stub shim.ChaincodeStubInterface) pb.Response {
    43  	// best practice to do nothing (or very little) in Init
    44  	return shim.Success(nil)
    45  }
    46  
    47  // Invoke is called to validate the specified block of transactions
    48  // This validation system chaincode will check the read-write set validity and at least 1
    49  // correct endorsement. Later we can create more validation system
    50  // chaincodes to provide more sophisticated policy processing such as enabling
    51  // policy specification to be coded as a transaction of the chaincode and the client
    52  // selecting which policy to use for validation using parameter function
    53  // @return serialized Block of valid and invalid transactions indentified
    54  // Note that Peer calls this function with 3 arguments, where args[0] is the
    55  // function name, args[1] is the Envelope and args[2] is the validation policy
    56  func (vscc *ValidatorOneValidSignature) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    57  	// TODO: document the argument in some white paper or design document
    58  	// args[0] - function name (not used now)
    59  	// args[1] - serialized Envelope
    60  	// args[2] - serialized policy
    61  	args := stub.GetArgs()
    62  	if len(args) < 3 {
    63  		return shim.Error("Incorrect number of arguments")
    64  	}
    65  
    66  	if args[1] == nil {
    67  		return shim.Error("No block to validate")
    68  	}
    69  
    70  	if args[2] == nil {
    71  		return shim.Error("No policy supplied")
    72  	}
    73  
    74  	logger.Debugf("VSCC invoked")
    75  
    76  	// get the envelope...
    77  	env, err := utils.GetEnvelopeFromBlock(args[1])
    78  	if err != nil {
    79  		logger.Errorf("VSCC error: GetEnvelope failed, err %s", err)
    80  		return shim.Error(err.Error())
    81  	}
    82  
    83  	// ...and the payload...
    84  	payl, err := utils.GetPayload(env)
    85  	if err != nil {
    86  		logger.Errorf("VSCC error: GetPayload failed, err %s", err)
    87  		return shim.Error(err.Error())
    88  	}
    89  
    90  	chdr, err := utils.UnmarshalChannelHeader(payl.Header.ChannelHeader)
    91  	if err != nil {
    92  		return shim.Error(err.Error())
    93  	}
    94  
    95  	// get the policy
    96  	mgr := mspmgmt.GetManagerForChain(chdr.ChannelId)
    97  	pProvider := cauthdsl.NewPolicyProvider(mgr)
    98  	policy, _, err := pProvider.NewPolicy(args[2])
    99  	if err != nil {
   100  		logger.Errorf("VSCC error: pProvider.NewPolicy failed, err %s", err)
   101  		return shim.Error(err.Error())
   102  	}
   103  
   104  	// validate the payload type
   105  	if common.HeaderType(chdr.Type) != common.HeaderType_ENDORSER_TRANSACTION {
   106  		logger.Errorf("Only Endorser Transactions are supported, provided type %d", chdr.Type)
   107  		return shim.Error(fmt.Sprintf("Only Endorser Transactions are supported, provided type %d", chdr.Type))
   108  	}
   109  
   110  	// ...and the transaction...
   111  	tx, err := utils.GetTransaction(payl.Data)
   112  	if err != nil {
   113  		logger.Errorf("VSCC error: GetTransaction failed, err %s", err)
   114  		return shim.Error(err.Error())
   115  	}
   116  
   117  	// loop through each of the actions within
   118  	for _, act := range tx.Actions {
   119  		cap, err := utils.GetChaincodeActionPayload(act.Payload)
   120  		if err != nil {
   121  			logger.Errorf("VSCC error: GetChaincodeActionPayload failed, err %s", err)
   122  			return shim.Error(err.Error())
   123  		}
   124  
   125  		// this is the first part of the signed message
   126  		prespBytes := cap.Action.ProposalResponsePayload
   127  		// build the signature set for the evaluation
   128  		signatureSet := make([]*common.SignedData, len(cap.Action.Endorsements))
   129  
   130  		// loop through each of the endorsements and build the signature set
   131  		for i, endorsement := range cap.Action.Endorsements {
   132  			signatureSet[i] = &common.SignedData{
   133  				// set the data that is signed; concatenation of proposal response bytes and endorser ID
   134  				Data: append(prespBytes, endorsement.Endorser...),
   135  				// set the identity that signs the message: it's the endorser
   136  				Identity: endorsement.Endorser,
   137  				// set the signature
   138  				Signature: endorsement.Signature,
   139  			}
   140  		}
   141  
   142  		// evaluate the signature set against the policy
   143  		err = policy.Evaluate(signatureSet)
   144  		if err != nil {
   145  			return shim.Error(fmt.Sprintf("VSCC error: policy evaluation failed, err %s", err))
   146  		}
   147  
   148  		hdrExt, err := utils.GetChaincodeHeaderExtension(payl.Header)
   149  		if err != nil {
   150  			logger.Errorf("VSCC error: GetChaincodeHeaderExtension failed, err %s", err)
   151  			return shim.Error(err.Error())
   152  		}
   153  
   154  		// do some extra validation that is specific to lscc
   155  		if hdrExt.ChaincodeId.Name == "lscc" {
   156  			err = vscc.ValidateLSCCInvocation(cap)
   157  			if err != nil {
   158  				logger.Errorf("VSCC error: ValidateLSCCInvocation failed, err %s", err)
   159  				return shim.Error(err.Error())
   160  			}
   161  		}
   162  	}
   163  
   164  	logger.Debugf("VSCC exists successfully")
   165  
   166  	return shim.Success(nil)
   167  }
   168  
   169  func (vscc *ValidatorOneValidSignature) ValidateLSCCInvocation(cap *pb.ChaincodeActionPayload) error {
   170  	cpp, err := utils.GetChaincodeProposalPayload(cap.ChaincodeProposalPayload)
   171  	if err != nil {
   172  		logger.Errorf("VSCC error: GetChaincodeProposalPayload failed, err %s", err)
   173  		return err
   174  	}
   175  
   176  	cis := &pb.ChaincodeInvocationSpec{}
   177  	err = proto.Unmarshal(cpp.Input, cis)
   178  	if err != nil {
   179  		logger.Errorf("VSCC error: Unmarshal ChaincodeInvocationSpec failed, err %s", err)
   180  		return err
   181  	}
   182  
   183  	if cis == nil ||
   184  		cis.ChaincodeSpec == nil ||
   185  		cis.ChaincodeSpec.Input == nil ||
   186  		cis.ChaincodeSpec.Input.Args == nil {
   187  		logger.Errorf("VSCC error: committing invalid vscc invocation")
   188  		return fmt.Errorf("VSCC error: committing invalid vscc invocation")
   189  	}
   190  
   191  	lsccFunc := string(cis.ChaincodeSpec.Input.Args[0])
   192  	lsccArgs := cis.ChaincodeSpec.Input.Args[1:]
   193  
   194  	switch lsccFunc {
   195  	case lscc.DEPLOY:
   196  	case lscc.UPGRADE:
   197  		logger.Infof("VSCC info: validating invocation of lscc function %s on arguments %#v", lsccFunc, lsccArgs)
   198  
   199  		// TODO: two more crs are expected to fill this gap, as explained in FAB-3155
   200  		// 1) check that the invocation complies with the InstantiationPolicy
   201  		// 2) check that the read/write set is appropriate
   202  
   203  		return nil
   204  	default:
   205  		return fmt.Errorf("VSCC error: committing an invocation of function %s of lscc is invalid", lsccFunc)
   206  	}
   207  
   208  	return nil
   209  }