// ValidateAndPrepareBatch implements method in Validator interface func (v *Validator) ValidateAndPrepareBatch(block *common.Block, doMVCCValidation bool) (*statedb.UpdateBatch, error) { logger.Debugf("New block arrived for validation:%#v, doMVCCValidation=%t", block, doMVCCValidation) var valid bool updates := statedb.NewUpdateBatch() logger.Debugf("Validating a block with [%d] transactions", len(block.Data.Data)) txsFilter := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) for txIndex, envBytes := range block.Data.Data { if txsFilter.IsSet(uint(txIndex)) { // Skiping invalid transaction logger.Debug("Skipping transaction marked as invalid, txIndex=", txIndex) continue } // extract actions from the envelope message respPayload, err := putils.GetActionFromEnvelope(envBytes) if err != nil { return nil, err } //preparation for extracting RWSet from transaction txRWSet := &rwset.TxReadWriteSet{} // Get the Result from the Action // and then Unmarshal it into a TxReadWriteSet using custom unmarshalling if err = txRWSet.Unmarshal(respPayload.Results); err != nil { return nil, err } // trace the first 2000 characters of RWSet only, in case it is huge if logger.IsEnabledFor(logging.DEBUG) { txRWSetString := txRWSet.String() if len(txRWSetString) < 2000 { logger.Debugf("validating txRWSet:[%s]", txRWSetString) } else { logger.Debugf("validating txRWSet:[%s...]", txRWSetString[0:2000]) } } if !doMVCCValidation { valid = true } else if valid, err = v.validateTx(txRWSet, updates); err != nil { return nil, err } if valid { committingTxHeight := version.NewHeight(block.Header.Number, uint64(txIndex+1)) addWriteSetToBatch(txRWSet, committingTxHeight, updates) } else { // Unset bit in byte array corresponded to the invalid transaction txsFilter.Set(uint(txIndex)) } } block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter.ToBytes() return updates, nil }
// ValidateAndPrepare implements method in interface `txmgmt.TxMgr` func (txmgr *CouchDBTxMgr) ValidateAndPrepare(block *common.Block, doMVCCValidation bool) error { if doMVCCValidation == true { logger.Debugf("===COUCHDB=== Entering CouchDBTxMgr.ValidateAndPrepare()") logger.Debugf("Validating a block with [%d] transactions", len(block.Data.Data)) } else { logger.Debugf("New block arrived for write set computation:%#v", block) logger.Debugf("Computing write set for a block with [%d] transactions", len(block.Data.Data)) } var valid bool txmgr.updateSet = newUpdateSet() txmgr.blockNum = block.Header.Number txsFilter := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) for txIndex, envBytes := range block.Data.Data { if txsFilter.IsSet(uint(txIndex)) { // Skiping invalid transaction logger.Debug("Skipping transaction marked as invalid, txIndex=", txIndex) continue } // extract actions from the envelope message respPayload, err := putils.GetActionFromEnvelope(envBytes) if err != nil { return err } //preparation for extracting RWSet from transaction txRWSet := &rwset.TxReadWriteSet{} // Get the Result from the Action // and then Unmarshal it into a TxReadWriteSet using custom unmarshalling if err = txRWSet.Unmarshal(respPayload.Results); err != nil { return err } // trace the first 2000 characters of RWSet only, in case it is huge if logger.IsEnabledFor(logging.DEBUG) { txRWSetString := txRWSet.String() operation := "validating" if doMVCCValidation == false { operation = "computing write set from" } if len(txRWSetString) < 2000 { logger.Debugf(operation+" txRWSet:[%s]", txRWSetString) } else { logger.Debugf(operation+" txRWSet:[%s...]", txRWSetString[0:2000]) } } if doMVCCValidation == true { if valid, err = txmgr.validateTx(txRWSet); err != nil { return err } } else { valid = true } if valid { if err := txmgr.addWriteSetToBatch(txRWSet, version.NewHeight(block.Header.Number, uint64(txIndex+1))); err != nil { return err } } else { // Unset bit in byte array corresponded to the invalid transaction txsFilter.Set(uint(txIndex)) } } block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter.ToBytes() logger.Debugf("===COUCHDB=== Exiting CouchDBTxMgr.ValidateAndPrepare()") return nil }
// Commit implements method in interface `histmgmt.HistMgr` // This writes to a separate history database. // TODO dpending on how invalid transactions are handled may need to filter what history commits. func (histmgr *CouchDBHistMgr) Commit(block *common.Block) error { logger.Debugf("===HISTORYDB=== Entering CouchDBHistMgr.Commit()") //Get the blocknumber off of the header blockNo := block.Header.Number //Set the starting tranNo to 0 var tranNo uint64 logger.Debugf("===HISTORYDB=== Updating history for blockNo: %v with [%d] transactions", blockNo, len(block.Data.Data)) for _, envBytes := range block.Data.Data { tranNo++ logger.Debugf("===HISTORYDB=== Updating history for tranNo: %v", tranNo) // extract actions from the envelope message respPayload, err := putils.GetActionFromEnvelope(envBytes) if err != nil { return err } //preparation for extracting RWSet from transaction txRWSet := &rwset.TxReadWriteSet{} // Get the Result from the Action and then Unmarshal // it into a TxReadWriteSet using custom unmarshalling if err = txRWSet.Unmarshal(respPayload.Results); err != nil { return err } //Transactions that have data that is not JSON such as binary data, // the write value will not write to history database. //These types of transactions will have the key written to the history // database to support history key scans. We do not write the binary // value to CouchDB since the purpose of the history database value is // for query andbinary data can not be queried. for _, nsRWSet := range txRWSet.NsRWs { ns := nsRWSet.NameSpace for _, kvWrite := range nsRWSet.Writes { writeKey := kvWrite.Key writeValue := kvWrite.Value compositeKey := constructCompositeKey(ns, writeKey, blockNo, tranNo) var bytesDoc []byte logger.Debugf("===HISTORYDB=== ns (namespace or cc id) = %v, writeKey: %v, compositeKey: %v, writeValue = %v", ns, writeKey, compositeKey, writeValue) if couchdb.IsJSON(string(writeValue)) { //logger.Debugf("===HISTORYDB=== yes JSON store writeValue = %v", string(writeValue)) bytesDoc = writeValue } else { //For data that is not in JSON format only store the key //logger.Debugf("===HISTORYDB=== not JSON only store key") bytesDoc = []byte(`{}`) } // SaveDoc using couchdb client and use JSON format rev, err := histmgr.couchDB.SaveDoc(compositeKey, "", bytesDoc, nil) if err != nil { logger.Errorf("===HISTORYDB=== Error during Commit(): %s\n", err.Error()) return err } if rev != "" { logger.Debugf("===HISTORYDB=== Saved document revision number: %s\n", rev) } } } } return nil }