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

Generated by: LCOV version 1.13