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
|