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