LCOV - code coverage report
Current view: top level - shared_model/validators - transaction_validator.hpp (source / functions) Hit Total Coverage
Test: coverage_cleared.info Lines: 144 144 100.0 %
Date: 2018-12-05 17:11:35 Functions: 43 43 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             : #ifndef IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP
       7             : #define IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP
       8             : 
       9             : #include <boost/format.hpp>
      10             : #include <boost/variant.hpp>
      11             : 
      12             : #include "interfaces/commands/add_asset_quantity.hpp"
      13             : #include "interfaces/commands/add_peer.hpp"
      14             : #include "interfaces/commands/add_signatory.hpp"
      15             : #include "interfaces/commands/append_role.hpp"
      16             : #include "interfaces/commands/command.hpp"
      17             : #include "interfaces/commands/create_account.hpp"
      18             : #include "interfaces/commands/create_asset.hpp"
      19             : #include "interfaces/commands/create_domain.hpp"
      20             : #include "interfaces/commands/create_role.hpp"
      21             : #include "interfaces/commands/detach_role.hpp"
      22             : #include "interfaces/commands/grant_permission.hpp"
      23             : #include "interfaces/commands/remove_signatory.hpp"
      24             : #include "interfaces/commands/revoke_permission.hpp"
      25             : #include "interfaces/commands/set_account_detail.hpp"
      26             : #include "interfaces/commands/set_quorum.hpp"
      27             : #include "interfaces/commands/subtract_asset_quantity.hpp"
      28             : #include "interfaces/commands/transfer_asset.hpp"
      29             : #include "interfaces/transaction.hpp"
      30             : #include "validators/abstract_validator.hpp"
      31             : #include "validators/answer.hpp"
      32             : 
      33             : namespace shared_model {
      34             :   namespace validation {
      35             : 
      36             :     /**
      37             :      * Visitor used by transaction validator to validate each command
      38             :      * @tparam FieldValidator - field validator type
      39             :      */
      40             :     template <typename FieldValidator>
      41             :     class CommandValidatorVisitor
      42             :         : public boost::static_visitor<ReasonsGroupType> {
      43             :      public:
      44             :       CommandValidatorVisitor(
      45             :           const FieldValidator &validator = FieldValidator())
      46        2147 :           : validator_(validator) {}
      47             : 
      48             :       ReasonsGroupType operator()(
      49             :           const interface::AddAssetQuantity &aaq) const {
      50         428 :         ReasonsGroupType reason;
      51         428 :         addInvalidCommand(reason, "AddAssetQuantity");
      52             : 
      53         428 :         validator_.validateAssetId(reason, aaq.assetId());
      54         428 :         validator_.validateAmount(reason, aaq.amount());
      55             : 
      56         428 :         return reason;
      57         428 :       }
      58             : 
      59             :       ReasonsGroupType operator()(const interface::AddPeer &ap) const {
      60         526 :         ReasonsGroupType reason;
      61         526 :         addInvalidCommand(reason, "AddPeer");
      62             : 
      63         526 :         validator_.validatePeer(reason, ap.peer());
      64             : 
      65         526 :         return reason;
      66         526 :       }
      67             : 
      68             :       ReasonsGroupType operator()(const interface::AddSignatory &as) const {
      69         379 :         ReasonsGroupType reason;
      70         379 :         addInvalidCommand(reason, "AddSignatory");
      71             : 
      72         379 :         validator_.validateAccountId(reason, as.accountId());
      73         379 :         validator_.validatePubkey(reason, as.pubkey());
      74             : 
      75         379 :         return reason;
      76         379 :       }
      77             : 
      78             :       ReasonsGroupType operator()(const interface::AppendRole &ar) const {
      79        1815 :         ReasonsGroupType reason;
      80        1815 :         addInvalidCommand(reason, "AppendRole");
      81             : 
      82        1815 :         validator_.validateAccountId(reason, ar.accountId());
      83        1815 :         validator_.validateRoleId(reason, ar.roleName());
      84             : 
      85        1815 :         return reason;
      86        1815 :       }
      87             : 
      88             :       ReasonsGroupType operator()(const interface::CreateAccount &ca) const {
      89        2129 :         ReasonsGroupType reason;
      90        2129 :         addInvalidCommand(reason, "CreateAccount");
      91             : 
      92        2129 :         validator_.validatePubkey(reason, ca.pubkey());
      93        2129 :         validator_.validateAccountName(reason, ca.accountName());
      94        2129 :         validator_.validateDomainId(reason, ca.domainId());
      95             : 
      96        2129 :         return reason;
      97        2129 :       }
      98             : 
      99             :       ReasonsGroupType operator()(const interface::CreateAsset &ca) const {
     100         758 :         ReasonsGroupType reason;
     101         758 :         addInvalidCommand(reason, "CreateAsset");
     102             : 
     103         758 :         validator_.validateAssetName(reason, ca.assetName());
     104         758 :         validator_.validateDomainId(reason, ca.domainId());
     105         758 :         validator_.validatePrecision(reason, ca.precision());
     106             : 
     107         758 :         return reason;
     108         758 :       }
     109             : 
     110             :       ReasonsGroupType operator()(const interface::CreateDomain &cd) const {
     111         890 :         ReasonsGroupType reason;
     112         890 :         addInvalidCommand(reason, "CreateDomain");
     113             : 
     114         890 :         validator_.validateDomainId(reason, cd.domainId());
     115         890 :         validator_.validateRoleId(reason, cd.userDefaultRole());
     116             : 
     117         890 :         return reason;
     118         890 :       }
     119             : 
     120             :       ReasonsGroupType operator()(const interface::CreateRole &cr) const {
     121        2343 :         ReasonsGroupType reason;
     122        2343 :         addInvalidCommand(reason, "CreateRole");
     123             : 
     124        2343 :         validator_.validateRoleId(reason, cr.roleName());
     125             :         cr.rolePermissions().iterate([&reason, this](auto i) {
     126       23377 :           validator_.validateRolePermission(reason, i);
     127       23377 :         });
     128             : 
     129        2343 :         return reason;
     130        2343 :       }
     131             : 
     132             :       ReasonsGroupType operator()(const interface::DetachRole &dr) const {
     133        1778 :         ReasonsGroupType reason;
     134        1778 :         addInvalidCommand(reason, "DetachRole");
     135             : 
     136        1778 :         validator_.validateAccountId(reason, dr.accountId());
     137        1778 :         validator_.validateRoleId(reason, dr.roleName());
     138             : 
     139        1778 :         return reason;
     140        1778 :       }
     141             : 
     142             :       ReasonsGroupType operator()(const interface::GrantPermission &gp) const {
     143          98 :         ReasonsGroupType reason;
     144          98 :         addInvalidCommand(reason, "GrantPermission");
     145             : 
     146          98 :         validator_.validateAccountId(reason, gp.accountId());
     147          98 :         validator_.validateGrantablePermission(reason, gp.permissionName());
     148             : 
     149          98 :         return reason;
     150          98 :       }
     151             : 
     152             :       ReasonsGroupType operator()(const interface::RemoveSignatory &rs) const {
     153          43 :         ReasonsGroupType reason;
     154          43 :         addInvalidCommand(reason, "RemoveSignatory");
     155             : 
     156          43 :         validator_.validateAccountId(reason, rs.accountId());
     157          43 :         validator_.validatePubkey(reason, rs.pubkey());
     158             : 
     159          43 :         return reason;
     160          43 :       }
     161             :       ReasonsGroupType operator()(const interface::RevokePermission &rp) const {
     162          34 :         ReasonsGroupType reason;
     163          34 :         addInvalidCommand(reason, "RevokePermission");
     164             : 
     165          34 :         validator_.validateAccountId(reason, rp.accountId());
     166          34 :         validator_.validateGrantablePermission(reason, rp.permissionName());
     167             : 
     168          34 :         return reason;
     169          34 :       }
     170             : 
     171             :       ReasonsGroupType operator()(
     172             :           const interface::SetAccountDetail &sad) const {
     173         222 :         ReasonsGroupType reason;
     174         222 :         addInvalidCommand(reason, "SetAccountDetail");
     175             : 
     176         222 :         validator_.validateAccountId(reason, sad.accountId());
     177         222 :         validator_.validateAccountDetailKey(reason, sad.key());
     178         222 :         validator_.validateAccountDetailValue(reason, sad.value());
     179             : 
     180         222 :         return reason;
     181         222 :       }
     182             : 
     183             :       ReasonsGroupType operator()(const interface::SetQuorum &sq) const {
     184         149 :         ReasonsGroupType reason;
     185         149 :         addInvalidCommand(reason, "SetQuorum");
     186             : 
     187         149 :         validator_.validateAccountId(reason, sq.accountId());
     188         149 :         validator_.validateQuorum(reason, sq.newQuorum());
     189             : 
     190         149 :         return reason;
     191         149 :       }
     192             : 
     193             :       ReasonsGroupType operator()(
     194             :           const interface::SubtractAssetQuantity &saq) const {
     195          20 :         ReasonsGroupType reason;
     196          20 :         addInvalidCommand(reason, "SubtractAssetQuantity");
     197             : 
     198          20 :         validator_.validateAssetId(reason, saq.assetId());
     199          20 :         validator_.validateAmount(reason, saq.amount());
     200             : 
     201          20 :         return reason;
     202          20 :       }
     203             : 
     204             :       ReasonsGroupType operator()(const interface::TransferAsset &ta) const {
     205         288 :         ReasonsGroupType reason;
     206         288 :         addInvalidCommand(reason, "TransferAsset");
     207             : 
     208         288 :         if (ta.srcAccountId() == ta.destAccountId()) {
     209           2 :           reason.second.emplace_back(
     210             :               "Source and destination accounts cannot be the same");
     211           2 :         }
     212             : 
     213         288 :         validator_.validateAccountId(reason, ta.srcAccountId());
     214         288 :         validator_.validateAccountId(reason, ta.destAccountId());
     215         288 :         validator_.validateAssetId(reason, ta.assetId());
     216         288 :         validator_.validateAmount(reason, ta.amount());
     217         288 :         validator_.validateDescription(reason, ta.description());
     218             : 
     219         288 :         return reason;
     220         288 :       }
     221             : 
     222             :      private:
     223             :       FieldValidator validator_;
     224        2147 :       mutable int command_counter{0};
     225             : 
     226             :       // adds command to a reason, appends and increments counter
     227             :       void addInvalidCommand(ReasonsGroupType &reason,
     228             :                              const std::string &command_name) const {
     229       11900 :         reason.first =
     230       11900 :             (boost::format("%d %s") % command_counter % command_name).str();
     231       11900 :         command_counter++;
     232       11900 :       }
     233             :     };
     234             : 
     235             :     /**
     236             :      * Class that validates commands from transaction
     237             :      * @tparam FieldValidator
     238             :      * @tparam CommandValidator
     239             :      */
     240             :     template <typename FieldValidator, typename CommandValidator>
     241             :     class TransactionValidator
     242             :         : public AbstractValidator<interface::Transaction> {
     243             :      private:
     244             :       template <typename CreatedTimeValidator>
     245             :       Answer validateImpl(const interface::Transaction &tx,
     246             :                           CreatedTimeValidator &&validator) const {
     247        3722 :         Answer answer;
     248        3722 :         std::string tx_reason_name = "Transaction";
     249        3722 :         ReasonsGroupType tx_reason(tx_reason_name, GroupedReasons());
     250             : 
     251        3722 :         if (tx.commands().empty()) {
     252           5 :           tx_reason.second.push_back(
     253           5 :               "Transaction should contain at least one command");
     254           5 :         }
     255             : 
     256        3722 :         field_validator_.validateCreatorAccountId(tx_reason,
     257        3722 :                                                   tx.creatorAccountId());
     258        3722 :         std::forward<CreatedTimeValidator>(validator)(tx_reason,
     259        3722 :                                                       tx.createdTime());
     260        3722 :         field_validator_.validateQuorum(tx_reason, tx.quorum());
     261        3722 :         if (tx.batchMeta() != boost::none)
     262          85 :           field_validator_.validateBatchMeta(tx_reason, **tx.batchMeta());
     263             : 
     264        3722 :         if (not tx_reason.second.empty()) {
     265          21 :           answer.addReason(std::move(tx_reason));
     266          21 :         }
     267             : 
     268       15636 :         for (const auto &command : tx.commands()) {
     269       11914 :           auto reason = boost::apply_visitor(command_validator_, command.get());
     270       11914 :           if (not reason.second.empty()) {
     271          65 :             answer.addReason(std::move(reason));
     272          65 :           }
     273       11914 :         }
     274             : 
     275        3722 :         return answer;
     276        3722 :       }
     277             : 
     278             :      public:
     279             :       explicit TransactionValidator(
     280             :           const FieldValidator &field_validator = FieldValidator(),
     281             :           const CommandValidator &command_validator = CommandValidator())
     282        2147 :           : field_validator_(field_validator),
     283        2147 :             command_validator_(command_validator) {}
     284             : 
     285             :       /**
     286             :        * Applies validation to given transaction
     287             :        * @param tx - transaction to validate
     288             :        * @return Answer containing found error if any
     289             :        */
     290             :       Answer validate(const interface::Transaction &tx) const override {
     291             :         return validateImpl(tx, [this](auto &reason, auto time) {
     292        1994 :           field_validator_.validateCreatedTime(reason, time);
     293        1994 :         });
     294             :       }
     295             : 
     296             :       /**
     297             :        * Validates transaction against current_timestamp instead of time
     298             :        * provider
     299             :        */
     300             :       Answer validate(const interface::Transaction &tx,
     301             :                       interface::types::TimestampType current_timestamp) const {
     302        1728 :         return validateImpl(tx,
     303             :                             [this, current_timestamp](auto &reason, auto time) {
     304        1728 :                               field_validator_.validateCreatedTime(
     305        1728 :                                   reason, time, current_timestamp);
     306        1728 :                             });
     307             :       }
     308             : 
     309             :      protected:
     310             :       FieldValidator field_validator_;
     311             :       CommandValidator command_validator_;
     312             :     };
     313             : 
     314             :   }  // namespace validation
     315             : }  // namespace shared_model
     316             : 
     317             : #endif  // IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP

Generated by: LCOV version 1.13