github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/core/committer/txvalidator/validator.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 txvalidator 18 19 import ( 20 "fmt" 21 22 "github.com/golang/protobuf/proto" 23 "github.com/hyperledger/fabric/common/configtx" 24 "github.com/hyperledger/fabric/common/flogging" 25 coreUtil "github.com/hyperledger/fabric/common/util" 26 "github.com/hyperledger/fabric/core/chaincode/shim" 27 "github.com/hyperledger/fabric/core/common/ccprovider" 28 "github.com/hyperledger/fabric/core/common/sysccprovider" 29 "github.com/hyperledger/fabric/core/common/validation" 30 "github.com/hyperledger/fabric/core/ledger" 31 ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" 32 "github.com/hyperledger/fabric/msp" 33 34 "github.com/hyperledger/fabric/protos/common" 35 "github.com/hyperledger/fabric/protos/peer" 36 "github.com/hyperledger/fabric/protos/utils" 37 "github.com/op/go-logging" 38 39 "github.com/hyperledger/fabric/common/cauthdsl" 40 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 41 ) 42 43 // Support provides all of the needed to evaluate the VSCC 44 type Support interface { 45 // Ledger returns the ledger associated with this validator 46 Ledger() ledger.PeerLedger 47 48 // MSPManager returns the MSP manager for this chain 49 MSPManager() msp.MSPManager 50 51 // Apply attempts to apply a configtx to become the new config 52 Apply(configtx *common.ConfigEnvelope) error 53 54 // GetMSPIDs returns the IDs for the application MSPs 55 // that have been defined in the channel 56 GetMSPIDs(cid string) []string 57 } 58 59 //Validator interface which defines API to validate block transactions 60 // and return the bit array mask indicating invalid transactions which 61 // didn't pass validation. 62 type Validator interface { 63 Validate(block *common.Block) error 64 } 65 66 // private interface to decouple tx validator 67 // and vscc execution, in order to increase 68 // testability of txValidator 69 type vsccValidator interface { 70 VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) 71 } 72 73 // vsccValidator implementation which used to call 74 // vscc chaincode and validate block transactions 75 type vsccValidatorImpl struct { 76 support Support 77 ccprovider ccprovider.ChaincodeProvider 78 sccprovider sysccprovider.SystemChaincodeProvider 79 } 80 81 // implementation of Validator interface, keeps 82 // reference to the ledger to enable tx simulation 83 // and execution of vscc 84 type txValidator struct { 85 support Support 86 vscc vsccValidator 87 } 88 89 var logger *logging.Logger // package-level logger 90 91 func init() { 92 // Init logger with module name 93 logger = flogging.MustGetLogger("txvalidator") 94 } 95 96 // NewTxValidator creates new transactions validator 97 func NewTxValidator(support Support) Validator { 98 // Encapsulates interface implementation 99 return &txValidator{support, 100 &vsccValidatorImpl{ 101 support: support, 102 ccprovider: ccprovider.GetChaincodeProvider(), 103 sccprovider: sysccprovider.GetSystemChaincodeProvider()}} 104 } 105 106 func (v *txValidator) chainExists(chain string) bool { 107 // TODO: implement this function! 108 return true 109 } 110 111 func (v *txValidator) Validate(block *common.Block) error { 112 logger.Debug("START Block Validation") 113 defer logger.Debug("END Block Validation") 114 // Initialize trans as valid here, then set invalidation reason code upon invalidation below 115 txsfltr := ledgerUtil.NewTxValidationFlags(len(block.Data.Data)) 116 // txsChaincodeNames records all the invoked chaincodes by tx in a block 117 txsChaincodeNames := make(map[int]*sysccprovider.ChaincodeInstance) 118 // upgradedChaincodes records all the chaincodes that are upgrded in a block 119 txsUpgradedChaincodes := make(map[int]*sysccprovider.ChaincodeInstance) 120 for tIdx, d := range block.Data.Data { 121 if d != nil { 122 if env, err := utils.GetEnvelopeFromBlock(d); err != nil { 123 logger.Warningf("Error getting tx from block(%s)", err) 124 txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON) 125 } else if env != nil { 126 // validate the transaction: here we check that the transaction 127 // is properly formed, properly signed and that the security 128 // chain binding proposal to endorsements to tx holds. We do 129 // NOT check the validity of endorsements, though. That's a 130 // job for VSCC below 131 logger.Debug("Validating transaction peer.ValidateTransaction()") 132 var payload *common.Payload 133 var err error 134 var txResult peer.TxValidationCode 135 136 if payload, txResult = validation.ValidateTransaction(env); txResult != peer.TxValidationCode_VALID { 137 logger.Errorf("Invalid transaction with index %d", tIdx) 138 txsfltr.SetFlag(tIdx, txResult) 139 continue 140 } 141 142 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 143 if err != nil { 144 logger.Warningf("Could not unmarshal channel header, err %s, skipping", err) 145 txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON) 146 continue 147 } 148 149 channel := chdr.ChannelId 150 logger.Debugf("Transaction is for chain %s", channel) 151 152 if !v.chainExists(channel) { 153 logger.Errorf("Dropping transaction for non-existent chain %s", channel) 154 txsfltr.SetFlag(tIdx, peer.TxValidationCode_TARGET_CHAIN_NOT_FOUND) 155 continue 156 } 157 158 if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION { 159 // Check duplicate transactions 160 txID := chdr.TxId 161 if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil { 162 logger.Error("Duplicate transaction found, ", txID, ", skipping") 163 txsfltr.SetFlag(tIdx, peer.TxValidationCode_DUPLICATE_TXID) 164 continue 165 } 166 167 // Validate tx with vscc and policy 168 logger.Debug("Validating transaction vscc tx validate") 169 err, cde := v.vscc.VSCCValidateTx(payload, d, env) 170 if err != nil { 171 txID := txID 172 logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err) 173 txsfltr.SetFlag(tIdx, cde) 174 continue 175 } 176 177 invokeCC, upgradeCC, err := v.getTxCCInstance(payload) 178 if err != nil { 179 logger.Errorf("Get chaincode instance from transaction txId = %s returned error %s", txID, err) 180 txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON) 181 continue 182 } 183 txsChaincodeNames[tIdx] = invokeCC 184 if upgradeCC != nil { 185 logger.Infof("Find chaincode upgrade transaction for chaincode %s on chain %s with new version %s", upgradeCC.ChaincodeName, upgradeCC.ChainID, upgradeCC.ChaincodeVersion) 186 txsUpgradedChaincodes[tIdx] = upgradeCC 187 } 188 } else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG { 189 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 190 if err != nil { 191 err := fmt.Errorf("Error unmarshaling config which passed initial validity checks: %s", err) 192 logger.Critical(err) 193 return err 194 } 195 196 if err := v.support.Apply(configEnvelope); err != nil { 197 err := fmt.Errorf("Error validating config which passed initial validity checks: %s", err) 198 logger.Critical(err) 199 return err 200 } 201 logger.Debugf("config transaction received for chain %s", channel) 202 } else { 203 logger.Warningf("Unknown transaction type [%s] in block number [%d] transaction index [%d]", 204 common.HeaderType(chdr.Type), block.Header.Number, tIdx) 205 txsfltr.SetFlag(tIdx, peer.TxValidationCode_UNKNOWN_TX_TYPE) 206 continue 207 } 208 209 if _, err := proto.Marshal(env); err != nil { 210 logger.Warningf("Cannot marshal transaction due to %s", err) 211 txsfltr.SetFlag(tIdx, peer.TxValidationCode_MARSHAL_TX_ERROR) 212 continue 213 } 214 // Succeeded to pass down here, transaction is valid 215 txsfltr.SetFlag(tIdx, peer.TxValidationCode_VALID) 216 } else { 217 logger.Warning("Nil tx from block") 218 txsfltr.SetFlag(tIdx, peer.TxValidationCode_NIL_ENVELOPE) 219 } 220 } 221 } 222 223 txsfltr = v.invalidTXsForUpgradeCC(txsChaincodeNames, txsUpgradedChaincodes, txsfltr) 224 225 // Initialize metadata structure 226 utils.InitBlockMetadata(block) 227 228 block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr 229 230 return nil 231 } 232 233 // generateCCKey generates a unique identifier for chaincode in specific chain 234 func (v *txValidator) generateCCKey(ccName, chainID string) string { 235 return fmt.Sprintf("%s/%s", ccName, chainID) 236 } 237 238 // invalidTXsForUpgradeCC invalid all txs that should be invalided because of chaincode upgrade txs 239 func (v *txValidator) invalidTXsForUpgradeCC(txsChaincodeNames map[int]*sysccprovider.ChaincodeInstance, txsUpgradedChaincodes map[int]*sysccprovider.ChaincodeInstance, txsfltr ledgerUtil.TxValidationFlags) ledgerUtil.TxValidationFlags { 240 if len(txsUpgradedChaincodes) == 0 { 241 return txsfltr 242 } 243 244 // Invalid former cc upgrade txs if there're two or more txs upgrade the same cc 245 finalValidUpgradeTXs := make(map[string]int) 246 upgradedChaincodes := make(map[string]*sysccprovider.ChaincodeInstance) 247 for tIdx, cc := range txsUpgradedChaincodes { 248 if cc == nil { 249 continue 250 } 251 upgradedCCKey := v.generateCCKey(cc.ChaincodeName, cc.ChainID) 252 253 if finalIdx, exist := finalValidUpgradeTXs[upgradedCCKey]; !exist { 254 finalValidUpgradeTXs[upgradedCCKey] = tIdx 255 upgradedChaincodes[upgradedCCKey] = cc 256 } else if finalIdx < tIdx { 257 logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", finalIdx) 258 txsfltr.SetFlag(finalIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 259 260 // record latter cc upgrade tx info 261 finalValidUpgradeTXs[upgradedCCKey] = tIdx 262 upgradedChaincodes[upgradedCCKey] = cc 263 } else { 264 logger.Infof("Invalid transaction with index %d: chaincode was upgraded by latter tx", tIdx) 265 txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 266 } 267 } 268 269 // invalid txs which invoke the upgraded chaincodes 270 for tIdx, cc := range txsChaincodeNames { 271 if cc == nil { 272 continue 273 } 274 ccKey := v.generateCCKey(cc.ChaincodeName, cc.ChainID) 275 if _, exist := upgradedChaincodes[ccKey]; exist { 276 if txsfltr.IsValid(tIdx) { 277 logger.Infof("Invalid transaction with index %d: chaincode was upgraded in the same block", tIdx) 278 txsfltr.SetFlag(tIdx, peer.TxValidationCode_CHAINCODE_VERSION_CONFLICT) 279 } 280 } 281 } 282 283 return txsfltr 284 } 285 286 func (v *txValidator) getTxCCInstance(payload *common.Payload) (invokeCCIns, upgradeCCIns *sysccprovider.ChaincodeInstance, err error) { 287 // This is duplicated unpacking work, but make test easier. 288 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 289 if err != nil { 290 return nil, nil, err 291 } 292 293 // Chain ID 294 chainID := chdr.ChannelId // it is guaranteed to be an existing channel by now 295 296 // ChaincodeID 297 hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) 298 if err != nil { 299 return nil, nil, err 300 } 301 invokeCC := hdrExt.ChaincodeId 302 invokeIns := &sysccprovider.ChaincodeInstance{ChainID: chainID, ChaincodeName: invokeCC.Name, ChaincodeVersion: invokeCC.Version} 303 304 // Transaction 305 tx, err := utils.GetTransaction(payload.Data) 306 if err != nil { 307 logger.Errorf("GetTransaction failed: %s", err) 308 return invokeIns, nil, nil 309 } 310 311 // ChaincodeActionPayload 312 cap, err := utils.GetChaincodeActionPayload(tx.Actions[0].Payload) 313 if err != nil { 314 logger.Errorf("GetChaincodeActionPayload failed: %s", err) 315 return invokeIns, nil, nil 316 } 317 318 // ChaincodeProposalPayload 319 cpp, err := utils.GetChaincodeProposalPayload(cap.ChaincodeProposalPayload) 320 if err != nil { 321 logger.Errorf("GetChaincodeProposalPayload failed: %s", err) 322 return invokeIns, nil, nil 323 } 324 325 // ChaincodeInvocationSpec 326 cis := &peer.ChaincodeInvocationSpec{} 327 err = proto.Unmarshal(cpp.Input, cis) 328 if err != nil { 329 logger.Errorf("GetChaincodeInvokeSpec failed: %s", err) 330 return invokeIns, nil, nil 331 } 332 333 if invokeCC.Name == "lscc" { 334 if string(cis.ChaincodeSpec.Input.Args[0]) == "upgrade" { 335 upgradeIns, err := v.getUpgradeTxInstance(chainID, cis.ChaincodeSpec.Input.Args[2]) 336 if err != nil { 337 return invokeIns, nil, nil 338 } 339 return invokeIns, upgradeIns, nil 340 } 341 } 342 343 return invokeIns, nil, nil 344 } 345 346 func (v *txValidator) getUpgradeTxInstance(chainID string, cdsBytes []byte) (*sysccprovider.ChaincodeInstance, error) { 347 cds, err := utils.GetChaincodeDeploymentSpec(cdsBytes) 348 if err != nil { 349 return nil, err 350 } 351 352 return &sysccprovider.ChaincodeInstance{ 353 ChainID: chainID, 354 ChaincodeName: cds.ChaincodeSpec.ChaincodeId.Name, 355 ChaincodeVersion: cds.ChaincodeSpec.ChaincodeId.Version, 356 }, nil 357 } 358 359 // GetInfoForValidate gets the ChaincodeInstance(with latest version) of tx, vscc and policy from lscc 360 func (v *vsccValidatorImpl) GetInfoForValidate(txid, chID, ccID string) (*sysccprovider.ChaincodeInstance, *sysccprovider.ChaincodeInstance, []byte, error) { 361 cc := &sysccprovider.ChaincodeInstance{ChainID: chID} 362 vscc := &sysccprovider.ChaincodeInstance{ChainID: chID} 363 var policy []byte 364 var err error 365 if ccID != "lscc" { 366 // when we are validating any chaincode other than 367 // LSCC, we need to ask LSCC to give us the name 368 // of VSCC and of the policy that should be used 369 370 // obtain name of the VSCC and the policy from LSCC 371 cd, err := v.getCDataForCC(ccID) 372 if err != nil { 373 logger.Errorf("Unable to get chaincode data from ledger for txid %s, due to %s", txid, err) 374 return nil, nil, nil, err 375 } 376 cc.ChaincodeName = cd.Name 377 cc.ChaincodeVersion = cd.Version 378 vscc.ChaincodeName = cd.Vscc 379 policy = cd.Policy 380 } else { 381 // when we are validating LSCC, we use the default 382 // VSCC and a default policy that requires one signature 383 // from any of the members of the channel 384 cc.ChaincodeName = "lscc" 385 cc.ChaincodeVersion = coreUtil.GetSysCCVersion() 386 vscc.ChaincodeName = "vscc" 387 p := cauthdsl.SignedByAnyMember(v.support.GetMSPIDs(chID)) 388 policy, err = utils.Marshal(p) 389 if err != nil { 390 return nil, nil, nil, err 391 } 392 } 393 394 // Get vscc version 395 vscc.ChaincodeVersion = coreUtil.GetSysCCVersion() 396 397 return cc, vscc, policy, nil 398 } 399 400 func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte, env *common.Envelope) (error, peer.TxValidationCode) { 401 // get header extensions so we have the chaincode ID 402 hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) 403 if err != nil { 404 return err, peer.TxValidationCode_BAD_HEADER_EXTENSION 405 } 406 407 // get channel header 408 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 409 if err != nil { 410 return err, peer.TxValidationCode_BAD_CHANNEL_HEADER 411 } 412 413 /* obtain the list of namespaces we're writing stuff to; 414 at first, we establish a few facts about this invocation: 415 1) which namespaces does it write to? 416 2) does it write to LSCC's namespace? 417 3) does it write to any cc that cannot be invoked? */ 418 wrNamespace := []string{} 419 writesToLSCC := false 420 writesToNonInvokableSCC := false 421 respPayload, err := utils.GetActionFromEnvelope(envBytes) 422 if err != nil { 423 return fmt.Errorf("GetActionFromEnvelope failed, error %s", err), peer.TxValidationCode_BAD_RESPONSE_PAYLOAD 424 } 425 txRWSet := &rwsetutil.TxRwSet{} 426 if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { 427 return fmt.Errorf("txRWSet.FromProtoBytes failed, error %s", err), peer.TxValidationCode_BAD_RWSET 428 } 429 for _, ns := range txRWSet.NsRwSets { 430 if len(ns.KvRwSet.Writes) > 0 { 431 wrNamespace = append(wrNamespace, ns.NameSpace) 432 433 if !writesToLSCC && ns.NameSpace == "lscc" { 434 writesToLSCC = true 435 } 436 437 if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableCC2CC(ns.NameSpace) { 438 writesToNonInvokableSCC = true 439 } 440 441 if !writesToNonInvokableSCC && v.sccprovider.IsSysCCAndNotInvokableExternal(ns.NameSpace) { 442 writesToNonInvokableSCC = true 443 } 444 } 445 } 446 447 // get name and version of the cc we invoked 448 ccID := hdrExt.ChaincodeId.Name 449 ccVer := respPayload.ChaincodeId.Version 450 451 // sanity check on ccID 452 if ccID == "" { 453 err := fmt.Errorf("invalid chaincode ID") 454 logger.Errorf("%s", err) 455 return err, peer.TxValidationCode_INVALID_OTHER_REASON 456 } 457 if ccID != respPayload.ChaincodeId.Name { 458 err := fmt.Errorf("inconsistent ccid info (%s/%s)", ccID, respPayload.ChaincodeId.Name) 459 logger.Errorf("%s", err) 460 return err, peer.TxValidationCode_INVALID_OTHER_REASON 461 } 462 // sanity check on ccver 463 if ccVer == "" { 464 err := fmt.Errorf("invalid chaincode version") 465 logger.Errorf("%s", err) 466 return err, peer.TxValidationCode_INVALID_OTHER_REASON 467 } 468 469 // we've gathered all the info required to proceed to validation; 470 // validation will behave differently depending on the type of 471 // chaincode (system vs. application) 472 473 if !v.sccprovider.IsSysCC(ccID) { 474 // if we're here, we know this is an invocation of an application chaincode; 475 // first of all, we make sure that: 476 // 1) we don't write to LSCC - an application chaincode is free to invoke LSCC 477 // for instance to get information about itself or another chaincode; however 478 // these legitimate invocations only ready from LSCC's namespace; currently 479 // only two functions of LSCC write to its namespace: deploy and upgrade and 480 // neither should be used by an application chaincode 481 if writesToLSCC { 482 return fmt.Errorf("Chaincode %s attempted to write to the namespace of LSCC", ccID), 483 peer.TxValidationCode_ILLEGAL_WRITESET 484 } 485 // 2) we don't write to the namespace of a chaincode that we cannot invoke - if 486 // the chaincode cannot be invoked in the first place, there's no legitimate 487 // way in which a transaction has a write set that writes to it; additionally 488 // we don't have any means of verifying whether the transaction had the rights 489 // to perform that write operation because in v1, system chaincodes do not have 490 // any endorsement policies to speak of. So if the chaincode can't be invoked 491 // it can't be written to by an invocation of an application chaincode 492 if writesToNonInvokableSCC { 493 return fmt.Errorf("Chaincode %s attempted to write to the namespace of a system chaincode that cannot be invoked", ccID), 494 peer.TxValidationCode_ILLEGAL_WRITESET 495 } 496 497 // validate *EACH* read write set according to its chaincode's endorsement policy 498 for _, ns := range wrNamespace { 499 // Get latest chaincode version, vscc and validate policy 500 txcc, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ns) 501 if err != nil { 502 logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err) 503 return err, peer.TxValidationCode_INVALID_OTHER_REASON 504 } 505 506 // if the namespace corresponds to the cc that was originally 507 // invoked, we check that the version of the cc that was 508 // invoked corresponds to the version that lscc has returned 509 if ns == ccID && txcc.ChaincodeVersion != ccVer { 510 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) 511 logger.Errorf(err.Error()) 512 return err, peer.TxValidationCode_EXPIRED_CHAINCODE 513 } 514 515 // do VSCC validation 516 if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, chdr.ChannelId, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil { 517 return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err), 518 peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE 519 } 520 } 521 } else { 522 // make sure that we can invoke this system chaincode - if the chaincode 523 // cannot be invoked through a proposal to this peer, we have to drop the 524 // transaction; if we didn't, we wouldn't know how to decide whether it's 525 // valid or not because in v1, system chaincodes have no endorsement policy 526 if v.sccprovider.IsSysCCAndNotInvokableExternal(ccID) { 527 return fmt.Errorf("Committing an invocation of cc %s is illegal", ccID), 528 peer.TxValidationCode_ILLEGAL_WRITESET 529 } 530 531 // Get latest chaincode version, vscc and validate policy 532 _, vscc, policy, err := v.GetInfoForValidate(chdr.TxId, chdr.ChannelId, ccID) 533 if err != nil { 534 logger.Errorf("GetInfoForValidate for txId = %s returned error %s", chdr.TxId, err) 535 return err, peer.TxValidationCode_INVALID_OTHER_REASON 536 } 537 538 // validate the transaction as an invocation of this system chaincode; 539 // vscc will have to do custom validation for this system chaincode 540 // currently, VSCC does custom validation for LSCC only; if an hlf 541 // user creates a new system chaincode which is invokable from the outside 542 // they have to modify VSCC to provide appropriate validation 543 if err = v.VSCCValidateTxForCC(envBytes, chdr.TxId, vscc.ChainID, vscc.ChaincodeName, vscc.ChaincodeVersion, policy); err != nil { 544 return fmt.Errorf("VSCCValidateTxForCC failed for cc %s, error %s", ccID, err), 545 peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE 546 } 547 } 548 549 return nil, peer.TxValidationCode_VALID 550 } 551 552 func (v *vsccValidatorImpl) VSCCValidateTxForCC(envBytes []byte, txid, chid, vsccName, vsccVer string, policy []byte) error { 553 ctxt, err := v.ccprovider.GetContext(v.support.Ledger()) 554 if err != nil { 555 logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err) 556 return err 557 } 558 defer v.ccprovider.ReleaseContext() 559 560 // build arguments for VSCC invocation 561 // args[0] - function name (not used now) 562 // args[1] - serialized Envelope 563 // args[2] - serialized policy 564 args := [][]byte{[]byte(""), envBytes, policy} 565 566 // get context to invoke VSCC 567 vscctxid := coreUtil.GenerateUUID() 568 cccid := v.ccprovider.GetCCContext(chid, vsccName, vsccVer, vscctxid, true, nil, nil) 569 570 // invoke VSCC 571 logger.Debug("Invoking VSCC txid", txid, "chaindID", chid) 572 res, _, err := v.ccprovider.ExecuteChaincode(ctxt, cccid, args) 573 if err != nil { 574 logger.Errorf("Invoke VSCC failed for transaction txid=%s, error %s", txid, err) 575 return err 576 } 577 if res.Status != shim.OK { 578 logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, res.Message) 579 return fmt.Errorf("%s", res.Message) 580 } 581 582 return nil 583 } 584 585 func (v *vsccValidatorImpl) getCDataForCC(ccid string) (*ccprovider.ChaincodeData, error) { 586 l := v.support.Ledger() 587 if l == nil { 588 return nil, fmt.Errorf("nil ledger instance") 589 } 590 591 qe, err := l.NewQueryExecutor() 592 if err != nil { 593 return nil, fmt.Errorf("Could not retrieve QueryExecutor, error %s", err) 594 } 595 defer qe.Done() 596 597 bytes, err := qe.GetState("lscc", ccid) 598 if err != nil { 599 return nil, fmt.Errorf("Could not retrieve state for chaincode %s, error %s", ccid, err) 600 } 601 602 if bytes == nil { 603 return nil, fmt.Errorf("lscc's state for [%s] not found.", ccid) 604 } 605 606 cd := &ccprovider.ChaincodeData{} 607 err = proto.Unmarshal(bytes, cd) 608 if err != nil { 609 return nil, fmt.Errorf("Unmarshalling ChaincodeQueryResponse failed, error %s", err) 610 } 611 612 if cd.Vscc == "" { 613 return nil, fmt.Errorf("lscc's state for [%s] is invalid, vscc field must be set.", ccid) 614 } 615 616 if len(cd.Policy) == 0 { 617 return nil, fmt.Errorf("lscc's state for [%s] is invalid, policy field must be set.", ccid) 618 } 619 620 return cd, err 621 }