github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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 coreUtil "github.com/hyperledger/fabric/common/util" 25 "github.com/hyperledger/fabric/core/chaincode/shim" 26 "github.com/hyperledger/fabric/core/common/ccprovider" 27 "github.com/hyperledger/fabric/core/common/validation" 28 "github.com/hyperledger/fabric/core/ledger" 29 ledgerUtil "github.com/hyperledger/fabric/core/ledger/util" 30 "github.com/hyperledger/fabric/msp" 31 32 "github.com/hyperledger/fabric/protos/common" 33 "github.com/hyperledger/fabric/protos/peer" 34 "github.com/hyperledger/fabric/protos/utils" 35 "github.com/op/go-logging" 36 ) 37 38 // Support provides all of the needed to evaluate the VSCC 39 type Support interface { 40 // Ledger returns the ledger associated with this validator 41 Ledger() ledger.PeerLedger 42 43 // MSPManager returns the MSP manager for this chain 44 MSPManager() msp.MSPManager 45 46 // Apply attempts to apply a configtx to become the new config 47 Apply(configtx *common.ConfigEnvelope) error 48 } 49 50 //Validator interface which defines API to validate block transactions 51 // and return the bit array mask indicating invalid transactions which 52 // didn't pass validation. 53 type Validator interface { 54 Validate(block *common.Block) error 55 } 56 57 // private interface to decouple tx validator 58 // and vscc execution, in order to increase 59 // testability of txValidator 60 type vsccValidator interface { 61 VSCCValidateTx(payload *common.Payload, envBytes []byte) error 62 } 63 64 // vsccValidator implementation which used to call 65 // vscc chaincode and validate block transactions 66 type vsccValidatorImpl struct { 67 support Support 68 ccprovider ccprovider.ChaincodeProvider 69 } 70 71 // implementation of Validator interface, keeps 72 // reference to the ledger to enable tx simulation 73 // and execution of vscc 74 type txValidator struct { 75 support Support 76 vscc vsccValidator 77 } 78 79 var logger *logging.Logger // package-level logger 80 81 func init() { 82 // Init logger with module name 83 logger = logging.MustGetLogger("txvalidator") 84 } 85 86 // NewTxValidator creates new transactions validator 87 func NewTxValidator(support Support) Validator { 88 // Encapsulates interface implementation 89 return &txValidator{support, &vsccValidatorImpl{support: support, ccprovider: ccprovider.GetChaincodeProvider()}} 90 } 91 92 func (v *txValidator) chainExists(chain string) bool { 93 // TODO: implement this function! 94 return true 95 } 96 97 func (v *txValidator) Validate(block *common.Block) error { 98 logger.Debug("START Block Validation") 99 defer logger.Debug("END Block Validation") 100 // Initialize trans as valid here, then set invalidation reason code upon invalidation below 101 txsfltr := ledgerUtil.NewTxValidationFlags(len(block.Data.Data)) 102 for tIdx, d := range block.Data.Data { 103 if d != nil { 104 if env, err := utils.GetEnvelopeFromBlock(d); err != nil { 105 logger.Warningf("Error getting tx from block(%s)", err) 106 txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON) 107 } else if env != nil { 108 // validate the transaction: here we check that the transaction 109 // is properly formed, properly signed and that the security 110 // chain binding proposal to endorsements to tx holds. We do 111 // NOT check the validity of endorsements, though. That's a 112 // job for VSCC below 113 logger.Debug("Validating transaction peer.ValidateTransaction()") 114 var payload *common.Payload 115 var err error 116 var txResult peer.TxValidationCode 117 118 if payload, txResult = validation.ValidateTransaction(env); txResult != peer.TxValidationCode_VALID { 119 logger.Errorf("Invalid transaction with index %d, error %s", tIdx, err) 120 txsfltr.SetFlag(tIdx, txResult) 121 continue 122 } 123 124 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 125 if err != nil { 126 logger.Warning("Could not unmarshal channel header, err %s, skipping", err) 127 txsfltr.SetFlag(tIdx, peer.TxValidationCode_INVALID_OTHER_REASON) 128 continue 129 } 130 131 channel := chdr.ChannelId 132 logger.Debug("Transaction is for chain %s", channel) 133 134 if !v.chainExists(channel) { 135 logger.Errorf("Dropping transaction for non-existent chain %s", channel) 136 txsfltr.SetFlag(tIdx, peer.TxValidationCode_TARGET_CHAIN_NOT_FOUND) 137 continue 138 } 139 140 if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION { 141 // Check duplicate transactions 142 txID := chdr.TxId 143 if _, err := v.support.Ledger().GetTransactionByID(txID); err == nil { 144 logger.Error("Duplicate transaction found, ", txID, ", skipping") 145 txsfltr.SetFlag(tIdx, peer.TxValidationCode_DUPLICATE_TXID) 146 continue 147 } 148 149 //the payload is used to get headers 150 logger.Debug("Validating transaction vscc tx validate") 151 if err = v.vscc.VSCCValidateTx(payload, d); err != nil { 152 txID := txID 153 logger.Errorf("VSCCValidateTx for transaction txId = %s returned error %s", txID, err) 154 txsfltr.SetFlag(tIdx, peer.TxValidationCode_ENDORSEMENT_POLICY_FAILURE) 155 continue 156 } 157 } else if common.HeaderType(chdr.Type) == common.HeaderType_CONFIG { 158 configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data) 159 if err != nil { 160 err := fmt.Errorf("Error unmarshaling config which passed initial validity checks: %s", err) 161 logger.Critical(err) 162 return err 163 } 164 165 if err := v.support.Apply(configEnvelope); err != nil { 166 err := fmt.Errorf("Error validating config which passed initial validity checks: %s", err) 167 logger.Critical(err) 168 return err 169 } 170 logger.Debugf("config transaction received for chain %s", channel) 171 } 172 173 if _, err := proto.Marshal(env); err != nil { 174 logger.Warningf("Cannot marshal transaction due to %s", err) 175 txsfltr.SetFlag(tIdx, peer.TxValidationCode_MARSHAL_TX_ERROR) 176 continue 177 } 178 // Succeeded to pass down here, transaction is valid 179 txsfltr.SetFlag(tIdx, peer.TxValidationCode_VALID) 180 } else { 181 logger.Warning("Nil tx from block") 182 txsfltr.SetFlag(tIdx, peer.TxValidationCode_NIL_ENVELOPE) 183 } 184 } 185 } 186 // Initialize metadata structure 187 utils.InitBlockMetadata(block) 188 189 block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsfltr 190 191 return nil 192 } 193 194 func (v *vsccValidatorImpl) VSCCValidateTx(payload *common.Payload, envBytes []byte) error { 195 chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 196 if err != nil { 197 return err 198 } 199 200 // Chain ID 201 chainID := chdr.ChannelId 202 if chainID == "" { 203 err := fmt.Errorf("transaction header does not contain an chain ID") 204 logger.Errorf("%s", err) 205 return err 206 } 207 208 // Get transaction id 209 txid := chdr.TxId 210 if txid == "" { 211 err := fmt.Errorf("transaction header does not contain transaction ID") 212 logger.Errorf("%s", err) 213 return err 214 } 215 216 ctxt, err := v.ccprovider.GetContext(v.support.Ledger()) 217 if err != nil { 218 logger.Errorf("Cannot obtain context for txid=%s, err %s", txid, err) 219 return err 220 } 221 defer v.ccprovider.ReleaseContext() 222 223 // get header extensions so we have the visibility field 224 hdrExt, err := utils.GetChaincodeHeaderExtension(payload.Header) 225 if err != nil { 226 return err 227 } 228 229 // LCCC should not undergo standard VSCC type of 230 // validation. It should instead go through system 231 // policy validation to determine whether the issuer 232 // is entitled to deploy a chaincode on our chain 233 // VSCCValidateTx should 234 if hdrExt.ChaincodeId.Name == "lccc" { 235 // TODO: until FAB-1934 is in, we need to stop here 236 logger.Debugf("Invocation of LCCC detected, no further VSCC validation necessary") 237 return nil 238 } 239 240 // obtain name of the VSCC and the policy from LCCC 241 vscc, policy, err := v.ccprovider.GetCCValidationInfoFromLCCC(ctxt, txid, nil, nil, chainID, hdrExt.ChaincodeId.Name) 242 if err != nil { 243 logger.Errorf("Unable to get chaincode data from LCCC for txid %s, due to %s", txid, err) 244 return err 245 } 246 247 // build arguments for VSCC invocation 248 // args[0] - function name (not used now) 249 // args[1] - serialized Envelope 250 // args[2] - serialized policy 251 args := [][]byte{[]byte(""), envBytes, policy} 252 253 vscctxid := coreUtil.GenerateUUID() 254 255 // Get chaincode version 256 version := coreUtil.GetSysCCVersion() 257 cccid := v.ccprovider.GetCCContext(chainID, vscc, version, vscctxid, true, nil, nil) 258 259 // invoke VSCC 260 logger.Debug("Invoking VSCC txid", txid, "chaindID", chainID) 261 res, _, err := v.ccprovider.ExecuteChaincode(ctxt, cccid, args) 262 if err != nil { 263 logger.Errorf("Invoke VSCC failed for transaction txid=%s, error %s", txid, err) 264 return err 265 } 266 if res.Status != shim.OK { 267 logger.Errorf("VSCC check failed for transaction txid=%s, error %s", txid, res.Message) 268 return fmt.Errorf("%s", res.Message) 269 } 270 271 return nil 272 }