// 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 }
func printBlocksInfo(block *common.Block) { // Read invalid transactions filter txsFltr := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) numOfInvalid := 0 // Count how many transaction indeed invalid for i := 0; i < len(block.Data.Data); i++ { if txsFltr.IsSet(uint(i)) { numOfInvalid++ } } fmt.Printf("Num txs in rawBlock = [%d], num invalidTxs = [%d]\n", len(block.Data.Data), numOfInvalid) }
func (h *txMgrTestHelper) checkRWsetInvalid(txRWSet []byte) { block := h.bg.NextBlock([][]byte{txRWSet}, false) err := h.txMgr.ValidateAndPrepare(block, true) testutil.AssertNoError(h.t, err, "") txsFltr := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) invalidTxNum := 0 for i := 0; i < len(block.Data.Data); i++ { if txsFltr.IsSet(uint(i)) { invalidTxNum++ } } testutil.AssertEquals(h.t, invalidTxNum, 1) }
func checkValidation(t *testing.T, validator *Validator, rwsets []*rwset.RWSet, invalidTxIndexes []int) { simulationResults := [][]byte{} for _, rwset := range rwsets { sr, err := rwset.GetTxReadWriteSet().Marshal() testutil.AssertNoError(t, err, "") simulationResults = append(simulationResults, sr) } block := testutil.ConstructBlock(t, simulationResults, false) _, err := validator.ValidateAndPrepareBatch(block, true) txsFltr := util.NewFilterBitArrayFromBytes(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) invalidTxNum := 0 for i := 0; i < len(block.Data.Data); i++ { if txsFltr.IsSet(uint(i)) { invalidTxNum++ } } testutil.AssertNoError(t, err, "") testutil.AssertEquals(t, invalidTxNum, len(invalidTxIndexes)) //TODO Add the check for exact txnum that is marked invlid when bitarray is in place }
// 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 }