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 "validation/utils.hpp"
18 :
19 : namespace iroha {
20 : namespace validation {
21 :
22 : /**
23 : * Complements initial transaction check with command-by-command check
24 : * @param temporary_wsv to apply commands on
25 : * @param transactions_errors_log to write errors to
26 : * @param tx to be checked
27 : * @return empty result, if check is successful, command error otherwise
28 : */
29 : static bool checkTransactions(
30 : ametsuchi::TemporaryWsv &temporary_wsv,
31 : validation::TransactionsErrors &transactions_errors_log,
32 : const shared_model::interface::Transaction &tx) {
33 733 : return temporary_wsv.apply(tx).match(
34 : [](expected::Value<void> &) { return true; },
35 : [&tx, &transactions_errors_log](
36 : expected::Error<validation::CommandError> &error) {
37 58 : transactions_errors_log.emplace(tx.hash(), std::move(error.error));
38 58 : return false;
39 : });
40 0 : };
41 :
42 : /**
43 : * Validate all transactions supplied; includes special rules, such as batch
44 : * validation etc
45 : * @param txs to be validated
46 : * @param temporary_wsv to apply transactions on
47 : * @param transactions_errors_log to write errors to
48 : * @param log to write errors to console
49 : * @param batch_parser to parse batches from transaction range
50 : * @return range of transactions, which passed stateful validation
51 : */
52 : static auto validateTransactions(
53 : const shared_model::interface::types::TransactionsCollectionType &txs,
54 : ametsuchi::TemporaryWsv &temporary_wsv,
55 : validation::TransactionsErrors &transactions_errors_log,
56 : const logger::Logger &log,
57 : const shared_model::interface::TransactionBatchParser &batch_parser) {
58 711 : std::vector<bool> validation_results;
59 711 : validation_results.reserve(boost::size(txs));
60 :
61 1437 : for (auto batch : batch_parser.parseBatches(txs)) {
62 : auto validation = [&](auto &tx) {
63 733 : return checkTransactions(temporary_wsv, transactions_errors_log, tx);
64 : };
65 726 : if (batch.front().batchMeta()
66 726 : 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 : }
78 :
79 4 : validation_results.insert(
80 4 : validation_results.end(), boost::size(batch), validation_result);
81 4 : } else {
82 : for (const auto &tx : batch) {
83 726 : validation_results.push_back(validation(tx));
84 : }
85 : }
86 726 : }
87 :
88 711 : return txs | boost::adaptors::indexed()
89 711 : | boost::adaptors::filtered(
90 : [validation_results =
91 711 : std::move(validation_results)](const auto &el) {
92 : return validation_results.at(el.index());
93 : })
94 711 : | boost::adaptors::transformed(
95 : [](const auto &el) -> decltype(auto) { return el.value(); });
96 711 : }
97 :
98 : StatefulValidatorImpl::StatefulValidatorImpl(
99 : std::unique_ptr<shared_model::interface::UnsafeProposalFactory> factory,
100 : std::shared_ptr<shared_model::interface::TransactionBatchParser>
101 : batch_parser)
102 : : factory_(std::move(factory)),
103 248 : batch_parser_(std::move(batch_parser)),
104 248 : log_(logger::log("SFV")) {}
105 :
106 : std::unique_ptr<validation::VerifiedProposalAndErrors>
107 : StatefulValidatorImpl::validate(
108 : const shared_model::interface::Proposal &proposal,
109 : ametsuchi::TemporaryWsv &temporaryWsv) {
110 711 : log_->info("transactions in proposal: {}",
111 711 : proposal.transactions().size());
112 :
113 711 : auto validation_result = std::make_unique<VerifiedProposalAndErrors>();
114 : auto valid_txs =
115 711 : validateTransactions(proposal.transactions(),
116 711 : temporaryWsv,
117 711 : validation_result->rejected_transactions,
118 711 : log_,
119 711 : *batch_parser_);
120 :
121 : // Since proposal came from ordering gate it was already validated.
122 : // All transactions has been validated as well
123 : // This allows for unsafe construction of proposal
124 711 : validation_result->verified_proposal = factory_->unsafeCreateProposal(
125 711 : proposal.height(), proposal.createdTime(), valid_txs);
126 :
127 711 : log_->info("transactions in verified proposal: {}",
128 711 : validation_result->verified_proposal->transactions().size());
129 711 : return validation_result;
130 711 : }
131 : } // namespace validation
132 : } // namespace iroha
|