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 }