LCOV - code coverage report
Current view: top level - irohad/ametsuchi/impl - temporary_wsv_impl.cpp (source / functions) Hit Total Coverage
Test: cleared_cor.info Lines: 72 83 86.7 %
Date: 2019-03-07 14:46:43 Functions: 22 22 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 "ametsuchi/impl/temporary_wsv_impl.hpp"
       7             : 
       8             : #include <boost/format.hpp>
       9             : #include "ametsuchi/impl/postgres_command_executor.hpp"
      10             : #include "cryptography/public_key.hpp"
      11             : #include "interfaces/commands/command.hpp"
      12             : #include "interfaces/permission_to_string.hpp"
      13             : #include "interfaces/transaction.hpp"
      14             : #include "logger/logger.hpp"
      15             : #include "logger/logger_manager.hpp"
      16             : 
      17             : namespace iroha {
      18             :   namespace ametsuchi {
      19             :     TemporaryWsvImpl::TemporaryWsvImpl(
      20             :         std::unique_ptr<soci::session> sql,
      21             :         std::shared_ptr<shared_model::interface::CommonObjectsFactory> factory,
      22             :         std::shared_ptr<shared_model::interface::PermissionToString>
      23             :             perm_converter,
      24             :         logger::LoggerManagerTreePtr log_manager)
      25         727 :         : sql_(std::move(sql)),
      26         727 :           command_executor_(std::make_unique<PostgresCommandExecutor>(
      27         727 :               *sql_, std::move(perm_converter))),
      28         727 :           log_manager_(std::move(log_manager)),
      29         727 :           log_(log_manager_->getLogger()) {
      30         727 :       *sql_ << "BEGIN";
      31         727 :     }
      32             : 
      33             :     expected::Result<void, validation::CommandError>
      34             :     TemporaryWsvImpl::validateSignatures(
      35             :         const shared_model::interface::Transaction &transaction) {
      36         732 :       auto keys_range = transaction.signatures()
      37         732 :           | boost::adaptors::transformed(
      38             :                             [](const auto &s) { return s.publicKey().hex(); });
      39         732 :       auto keys = std::accumulate(
      40         732 :           std::next(std::begin(keys_range)),
      41         732 :           std::end(keys_range),
      42         732 :           keys_range.front(),
      43             :           [](auto acc, const auto &val) { return acc + "'), ('" + val; });
      44             :       // not using bool since it is not supported by SOCI
      45         732 :       boost::optional<uint8_t> signatories_valid;
      46             : 
      47         732 :       boost::format query(R"(SELECT sum(count) = :signatures_count
      48             :                           AND sum(quorum) <= :signatures_count
      49             :                   FROM
      50             :                       (SELECT count(public_key)
      51             :                       FROM ( VALUES ('%s') ) AS CTE1(public_key)
      52             :                       WHERE public_key IN
      53             :                           (SELECT public_key
      54             :                           FROM account_has_signatory
      55             :                           WHERE account_id = :account_id ) ) AS CTE2(count),
      56             :                           (SELECT quorum
      57             :                           FROM account
      58             :                           WHERE account_id = :account_id) AS CTE3(quorum))");
      59             : 
      60             :       try {
      61         732 :         *sql_ << (query % keys).str(), soci::into(signatories_valid),
      62         732 :             soci::use(boost::size(keys_range), "signatures_count"),
      63         732 :             soci::use(transaction.creatorAccountId(), "account_id");
      64         732 :       } catch (const std::exception &e) {
      65           0 :         auto error_str = "Transaction " + transaction.toString()
      66           0 :             + " failed signatures validation with db error: " + e.what();
      67             :         // TODO [IR-1816] Akvinikym 29.10.18: substitute error code magic number
      68             :         // with named constant
      69           0 :         return expected::makeError(validation::CommandError{
      70           0 :             "signatures validation", 1, error_str, false});
      71           0 :       }
      72             : 
      73         732 :       if (signatories_valid and *signatories_valid) {
      74         726 :         return {};
      75             :       } else {
      76           6 :         auto error_str = "Transaction " + transaction.toString()
      77           6 :             + " failed signatures validation";
      78             :         // TODO [IR-1816] Akvinikym 29.10.18: substitute error code magic number
      79             :         // with named constant
      80           6 :         return expected::makeError(validation::CommandError{
      81           6 :             "signatures validation", 2, error_str, false});
      82           6 :       }
      83         732 :     }
      84             : 
      85             :     expected::Result<void, validation::CommandError> TemporaryWsvImpl::apply(
      86             :         const shared_model::interface::Transaction &transaction) {
      87         732 :       const auto &tx_creator = transaction.creatorAccountId();
      88         732 :       command_executor_->setCreatorAccountId(tx_creator);
      89         732 :       command_executor_->doValidation(true);
      90             :       auto execute_command =
      91             :           [this](auto &command) -> expected::Result<void, CommandError> {
      92             :         // Validate and execute command
      93        1922 :         return boost::apply_visitor(*command_executor_, command.get());
      94             :       };
      95             : 
      96         732 :       auto savepoint_wrapper = createSavepoint("savepoint_temp_wsv");
      97             : 
      98         732 :       return validateSignatures(transaction) |
      99             :                  [savepoint = std::move(savepoint_wrapper),
     100             :                   &execute_command,
     101         732 :                   &transaction]()
     102             :                  -> expected::Result<void, validation::CommandError> {
     103             :         // check transaction's commands validity
     104         726 :         const auto &commands = transaction.commands();
     105         726 :         validation::CommandError cmd_error;
     106        2596 :         for (size_t i = 0; i < commands.size(); ++i) {
     107             :           // in case of failed command, rollback and return
     108        1922 :           auto cmd_is_valid =
     109        1922 :               execute_command(commands[i])
     110             :                   .match([](expected::Value<void> &) { return true; },
     111             :                          [i, &cmd_error](expected::Error<CommandError> &error) {
     112          52 :                            cmd_error = {error.error.command_name,
     113          52 :                                         error.error.error_code,
     114          52 :                                         error.error.error_extra,
     115             :                                         true,
     116          52 :                                         i};
     117          52 :                            return false;
     118           0 :                          });
     119        1922 :           if (not cmd_is_valid) {
     120          52 :             return expected::makeError(cmd_error);
     121             :           }
     122        1870 :         }
     123             :         // success
     124         674 :         savepoint->release();
     125         674 :         return {};
     126         726 :       };
     127         732 :     }
     128             : 
     129             :     std::unique_ptr<TemporaryWsv::SavepointWrapper>
     130             :     TemporaryWsvImpl::createSavepoint(const std::string &name) {
     131         734 :       return std::make_unique<TemporaryWsvImpl::SavepointWrapperImpl>(
     132         734 :           SavepointWrapperImpl(
     133             :               *this,
     134         734 :               name,
     135         734 :               log_manager_->getChild("SavepointWrapper")->getLogger()));
     136           0 :     }
     137             : 
     138             :     TemporaryWsvImpl::~TemporaryWsvImpl() {
     139             :       try {
     140         727 :         *sql_ << "ROLLBACK";
     141         727 :       } catch (std::exception &e) {
     142           0 :         log_->error("Rollback did not happen: {}", e.what());
     143           0 :       }
     144         727 :     }
     145             : 
     146             :     TemporaryWsvImpl::SavepointWrapperImpl::SavepointWrapperImpl(
     147             :         const iroha::ametsuchi::TemporaryWsvImpl &wsv,
     148             :         std::string savepoint_name,
     149             :         logger::LoggerPtr log)
     150         734 :         : sql_{*wsv.sql_},
     151         734 :           savepoint_name_{std::move(savepoint_name)},
     152         734 :           is_released_{false},
     153         734 :           log_(std::move(log)) {
     154         734 :       sql_ << "SAVEPOINT " + savepoint_name_ + ";";
     155         734 :     }
     156             : 
     157             :     void TemporaryWsvImpl::SavepointWrapperImpl::release() {
     158         675 :       is_released_ = true;
     159         675 :     }
     160             : 
     161             :     TemporaryWsvImpl::SavepointWrapperImpl::~SavepointWrapperImpl() {
     162             :       try {
     163        1468 :         if (not is_released_) {
     164         793 :           sql_ << "ROLLBACK TO SAVEPOINT " + savepoint_name_ + ";";
     165         793 :         } else {
     166         675 :           sql_ << "RELEASE SAVEPOINT " + savepoint_name_ + ";";
     167             :         }
     168        1468 :       } catch (std::exception &e) {
     169           0 :         log_->error("SQL error. Reason: {}", e.what());
     170           0 :       }
     171        1468 :     }
     172             : 
     173             :   }  // namespace ametsuchi
     174             : }  // namespace iroha

Generated by: LCOV version 1.13