LCOV - code coverage report
Current view: top level - irohad/validation/impl - stateful_validator_impl.cpp (source / functions) Hit Total Coverage
Test: cleared_cor.info Lines: 61 63 96.8 %
Date: 2019-03-07 14:46:43 Functions: 14 14 100.0 %

          Line data    Source code
       1             : /**
       2             :  * Copyright Soramitsu Co., Ltd. All Rights Reserved.
       3             :  * SPDX-License-Identifier: Apache-2.0
       4             :  */
       5             : 
       6             : #include "validation/impl/stateful_validator_impl.hpp"
       7             : 
       8             : #include <string>
       9             : 
      10             : #include <boost/algorithm/cxx11/all_of.hpp>
      11             : #include <boost/format.hpp>
      12             : #include <boost/range/adaptor/filtered.hpp>
      13             : #include <boost/range/adaptor/indexed.hpp>
      14             : #include <boost/range/adaptor/transformed.hpp>
      15             : #include "common/result.hpp"
      16             : #include "interfaces/iroha_internal/batch_meta.hpp"
      17             : #include "logger/logger.hpp"
      18             : #include "validation/utils.hpp"
      19             : 
      20             : namespace iroha {
      21             :   namespace validation {
      22             : 
      23             :     /**
      24             :      * Complements initial transaction check with command-by-command check
      25             :      * @param temporary_wsv to apply commands on
      26             :      * @param transactions_errors_log to write errors to
      27             :      * @param tx to be checked
      28             :      * @return empty result, if check is successful, command error otherwise
      29             :      */
      30             :     static bool checkTransactions(
      31             :         ametsuchi::TemporaryWsv &temporary_wsv,
      32             :         validation::TransactionsErrors &transactions_errors_log,
      33             :         const shared_model::interface::Transaction &tx) {
      34         738 :       return temporary_wsv.apply(tx).match(
      35             :           [](expected::Value<void> &) { return true; },
      36             :           [&tx, &transactions_errors_log](
      37             :               expected::Error<validation::CommandError> &error) {
      38          60 :             transactions_errors_log.emplace_back(validation::TransactionError{
      39          60 :                 tx.hash(), std::move(error.error)});
      40          60 :             return false;
      41           0 :           });
      42           0 :     };
      43             : 
      44             :     /**
      45             :      * Validate all transactions supplied; includes special rules, such as batch
      46             :      * validation etc
      47             :      * @param txs to be validated
      48             :      * @param temporary_wsv to apply transactions on
      49             :      * @param transactions_errors_log to write errors to
      50             :      * @param batch_parser to parse batches from transaction range
      51             :      * @return range of transactions, which passed stateful validation
      52             :      */
      53             :     static auto validateTransactions(
      54             :         const shared_model::interface::types::TransactionsCollectionType &txs,
      55             :         ametsuchi::TemporaryWsv &temporary_wsv,
      56             :         validation::TransactionsErrors &transactions_errors_log,
      57             :         const shared_model::interface::TransactionBatchParser &batch_parser) {
      58         724 :       std::vector<bool> validation_results;
      59         724 :       validation_results.reserve(boost::size(txs));
      60             : 
      61        1455 :       for (auto batch : batch_parser.parseBatches(txs)) {
      62             :         auto validation = [&](auto &tx) {
      63         738 :           return checkTransactions(temporary_wsv, transactions_errors_log, tx);
      64             :         };
      65         731 :         if (batch.front().batchMeta()
      66         731 :             and batch.front().batchMeta()->get()->type()
      67           7 :                 == shared_model::interface::types::BatchType::ATOMIC) {
      68             :           // check all batch's transactions for validness
      69           4 :           auto savepoint = temporary_wsv.createSavepoint(
      70           4 :               "batch_" + batch.front().hash().hex());
      71           4 :           bool validation_result = false;
      72             : 
      73           4 :           if (boost::algorithm::all_of(batch, validation)) {
      74             :             // batch is successful; release savepoint
      75           2 :             validation_result = true;
      76           2 :             savepoint->release();
      77           2 :           } else {
      78           2 :             auto failed_tx_hash = transactions_errors_log.back().tx_hash;
      79           6 :             for (const auto &tx : batch) {
      80           4 :               if (tx.hash() != failed_tx_hash) {
      81           2 :                 transactions_errors_log.emplace_back(
      82           2 :                     validation::TransactionError{
      83           2 :                         tx.hash(),
      84             :                         // TODO igor-egorov 22.01.2019 IR-245 add a separate
      85             :                         // error code for failed batch case
      86           2 :                         validation::CommandError{
      87           2 :                             "",
      88             :                             1,  // internal error code
      89           2 :                             "Another transaction failed the batch",
      90             :                             true,
      91           2 :                             std::numeric_limits<size_t>::max()}});
      92           2 :               }
      93             :             }
      94           2 :           }
      95             : 
      96           4 :           validation_results.insert(
      97           4 :               validation_results.end(), boost::size(batch), validation_result);
      98           4 :         } else {
      99        1458 :           for (const auto &tx : batch) {
     100         731 :             validation_results.push_back(validation(tx));
     101             :           }
     102             :         }
     103         731 :       }
     104             : 
     105         724 :       return txs | boost::adaptors::indexed()
     106         724 :           | boost::adaptors::filtered(
     107             :                  [validation_results =
     108         724 :                       std::move(validation_results)](const auto &el) {
     109         739 :                    return validation_results.at(el.index());
     110             :                  })
     111         724 :           | boost::adaptors::transformed(
     112             :                  [](const auto &el) -> decltype(auto) { return el.value(); });
     113         724 :     }
     114             : 
     115             :     StatefulValidatorImpl::StatefulValidatorImpl(
     116             :         std::unique_ptr<shared_model::interface::UnsafeProposalFactory> factory,
     117             :         std::shared_ptr<shared_model::interface::TransactionBatchParser>
     118             :             batch_parser,
     119             :         logger::LoggerPtr log)
     120         250 :         : factory_(std::move(factory)),
     121         250 :           batch_parser_(std::move(batch_parser)),
     122         250 :           log_(std::move(log)) {}
     123             : 
     124             :     std::unique_ptr<validation::VerifiedProposalAndErrors>
     125             :     StatefulValidatorImpl::validate(
     126             :         const shared_model::interface::Proposal &proposal,
     127             :         ametsuchi::TemporaryWsv &temporaryWsv) {
     128         724 :       log_->info("transactions in proposal: {}",
     129         724 :                  proposal.transactions().size());
     130             : 
     131         724 :       auto validation_result = std::make_unique<VerifiedProposalAndErrors>();
     132             :       auto valid_txs =
     133         724 :           validateTransactions(proposal.transactions(),
     134         724 :                                temporaryWsv,
     135         724 :                                validation_result->rejected_transactions,
     136         724 :                                *batch_parser_);
     137             : 
     138             :       // Since proposal came from ordering gate it was already validated.
     139             :       // All transactions are validated as well
     140             :       // This allows for unsafe construction of proposal
     141         724 :       validation_result->verified_proposal =
     142         724 :           std::const_pointer_cast<const shared_model::interface::Proposal>(
     143         724 :               std::shared_ptr<shared_model::interface::Proposal>(
     144         724 :                   factory_->unsafeCreateProposal(
     145         724 :                       proposal.height(), proposal.createdTime(), valid_txs)));
     146             : 
     147         724 :       log_->info("transactions in verified proposal: {}",
     148         724 :                  validation_result->verified_proposal->transactions().size());
     149         724 :       return validation_result;
     150         724 :     }
     151             :   }  // namespace validation
     152             : }  // namespace iroha

Generated by: LCOV version 1.13