LCOV - code coverage report
Current view: top level - shared_model/validators - transaction_validator.hpp (source / functions) Hit Total Coverage
Test: cleared_cor.info Lines: 143 143 100.0 %
Date: 2019-03-07 14:46:43 Functions: 37 38 97.4 %

          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             :      * @note this class is not thread safe and never going to be
      40             :      * so copy constructor and assignment operator are disabled explicitly
      41             :      */
      42             :     template <typename FieldValidator>
      43             :     class CommandValidatorVisitor
      44             :         : public boost::static_visitor<ReasonsGroupType> {
      45             :      public:
      46             :       CommandValidatorVisitor(const CommandValidatorVisitor &) = delete;
      47             :       CommandValidatorVisitor &operator=(const CommandValidatorVisitor &) =
      48             :           delete;
      49             : 
      50             :       CommandValidatorVisitor(
      51             :           const FieldValidator &validator = FieldValidator())
      52       25149 :           : validator_(validator) {}
      53             : 
      54             :       ReasonsGroupType operator()(
      55             :           const interface::AddAssetQuantity &aaq) const {
      56        1346 :         ReasonsGroupType reason;
      57        1348 :         addInvalidCommand(reason, "AddAssetQuantity");
      58             : 
      59        1336 :         validator_.validateAssetId(reason, aaq.assetId());
      60        1362 :         validator_.validateAmount(reason, aaq.amount());
      61             : 
      62        1387 :         return reason;
      63        1387 :       }
      64             : 
      65             :       ReasonsGroupType operator()(const interface::AddPeer &ap) const {
      66         530 :         ReasonsGroupType reason;
      67         530 :         addInvalidCommand(reason, "AddPeer");
      68             : 
      69         530 :         validator_.validatePeer(reason, ap.peer());
      70             : 
      71         530 :         return reason;
      72         530 :       }
      73             : 
      74             :       ReasonsGroupType operator()(const interface::AddSignatory &as) const {
      75        1242 :         ReasonsGroupType reason;
      76        1242 :         addInvalidCommand(reason, "AddSignatory");
      77             : 
      78        1229 :         validator_.validateAccountId(reason, as.accountId());
      79        1271 :         validator_.validatePubkey(reason, as.pubkey());
      80             : 
      81        1281 :         return reason;
      82        1281 :       }
      83             : 
      84             :       ReasonsGroupType operator()(const interface::AppendRole &ar) const {
      85        3844 :         ReasonsGroupType reason;
      86        3844 :         addInvalidCommand(reason, "AppendRole");
      87             : 
      88        3837 :         validator_.validateAccountId(reason, ar.accountId());
      89        3872 :         validator_.validateRoleId(reason, ar.roleName());
      90             : 
      91        3900 :         return reason;
      92        3900 :       }
      93             : 
      94             :       ReasonsGroupType operator()(const interface::CreateAccount &ca) const {
      95        4568 :         ReasonsGroupType reason;
      96        4568 :         addInvalidCommand(reason, "CreateAccount");
      97             : 
      98        4556 :         validator_.validatePubkey(reason, ca.pubkey());
      99        4539 :         validator_.validateAccountName(reason, ca.accountName());
     100        4566 :         validator_.validateDomainId(reason, ca.domainId());
     101             : 
     102        4635 :         return reason;
     103        4638 :       }
     104             : 
     105             :       ReasonsGroupType operator()(const interface::CreateAsset &ca) const {
     106        1164 :         ReasonsGroupType reason;
     107        1164 :         addInvalidCommand(reason, "CreateAsset");
     108             : 
     109        1153 :         validator_.validateAssetName(reason, ca.assetName());
     110        1163 :         validator_.validateDomainId(reason, ca.domainId());
     111        1171 :         validator_.validatePrecision(reason, ca.precision());
     112             : 
     113        1178 :         return reason;
     114        1178 :       }
     115             : 
     116             :       ReasonsGroupType operator()(const interface::CreateDomain &cd) const {
     117        1301 :         ReasonsGroupType reason;
     118        1301 :         addInvalidCommand(reason, "CreateDomain");
     119             : 
     120        1293 :         validator_.validateDomainId(reason, cd.domainId());
     121        1304 :         validator_.validateRoleId(reason, cd.userDefaultRole());
     122             : 
     123        1318 :         return reason;
     124        1318 :       }
     125             : 
     126             :       ReasonsGroupType operator()(const interface::CreateRole &cr) const {
     127        4413 :         ReasonsGroupType reason;
     128        4413 :         addInvalidCommand(reason, "CreateRole");
     129             : 
     130        4393 :         validator_.validateRoleId(reason, cr.roleName());
     131             :         cr.rolePermissions().iterate([&reason, this](auto i) {
     132       28776 :           validator_.validateRolePermission(reason, i);
     133       28776 :         });
     134             : 
     135        4481 :         return reason;
     136        4481 :       }
     137             : 
     138             :       ReasonsGroupType operator()(const interface::DetachRole &dr) const {
     139        3704 :         ReasonsGroupType reason;
     140        3705 :         addInvalidCommand(reason, "DetachRole");
     141             : 
     142        3705 :         validator_.validateAccountId(reason, dr.accountId());
     143        3739 :         validator_.validateRoleId(reason, dr.roleName());
     144             : 
     145        3757 :         return reason;
     146        3764 :       }
     147             : 
     148             :       ReasonsGroupType operator()(const interface::GrantPermission &gp) const {
     149         357 :         ReasonsGroupType reason;
     150         357 :         addInvalidCommand(reason, "GrantPermission");
     151             : 
     152         356 :         validator_.validateAccountId(reason, gp.accountId());
     153         366 :         validator_.validateGrantablePermission(reason, gp.permissionName());
     154             : 
     155         370 :         return reason;
     156         370 :       }
     157             : 
     158             :       ReasonsGroupType operator()(const interface::RemoveSignatory &rs) const {
     159         122 :         ReasonsGroupType reason;
     160         124 :         addInvalidCommand(reason, "RemoveSignatory");
     161             : 
     162         124 :         validator_.validateAccountId(reason, rs.accountId());
     163         128 :         validator_.validatePubkey(reason, rs.pubkey());
     164             : 
     165         128 :         return reason;
     166         128 :       }
     167             :       ReasonsGroupType operator()(const interface::RevokePermission &rp) const {
     168         136 :         ReasonsGroupType reason;
     169         136 :         addInvalidCommand(reason, "RevokePermission");
     170             : 
     171         135 :         validator_.validateAccountId(reason, rp.accountId());
     172         142 :         validator_.validateGrantablePermission(reason, rp.permissionName());
     173             : 
     174         145 :         return reason;
     175         145 :       }
     176             : 
     177             :       ReasonsGroupType operator()(
     178             :           const interface::SetAccountDetail &sad) const {
     179         728 :         ReasonsGroupType reason;
     180         728 :         addInvalidCommand(reason, "SetAccountDetail");
     181             : 
     182         708 :         validator_.validateAccountId(reason, sad.accountId());
     183         725 :         validator_.validateAccountDetailKey(reason, sad.key());
     184         737 :         validator_.validateAccountDetailValue(reason, sad.value());
     185             : 
     186         753 :         return reason;
     187         753 :       }
     188             : 
     189             :       ReasonsGroupType operator()(const interface::SetQuorum &sq) const {
     190         223 :         ReasonsGroupType reason;
     191         223 :         addInvalidCommand(reason, "SetQuorum");
     192             : 
     193         221 :         validator_.validateAccountId(reason, sq.accountId());
     194         224 :         validator_.validateQuorum(reason, sq.newQuorum());
     195             : 
     196         225 :         return reason;
     197         225 :       }
     198             : 
     199             :       ReasonsGroupType operator()(
     200             :           const interface::SubtractAssetQuantity &saq) const {
     201          53 :         ReasonsGroupType reason;
     202          53 :         addInvalidCommand(reason, "SubtractAssetQuantity");
     203             : 
     204          50 :         validator_.validateAssetId(reason, saq.assetId());
     205          54 :         validator_.validateAmount(reason, saq.amount());
     206             : 
     207          54 :         return reason;
     208          54 :       }
     209             : 
     210             :       ReasonsGroupType operator()(const interface::TransferAsset &ta) const {
     211         881 :         ReasonsGroupType reason;
     212         881 :         addInvalidCommand(reason, "TransferAsset");
     213             : 
     214         893 :         if (ta.srcAccountId() == ta.destAccountId()) {
     215           2 :           reason.second.emplace_back(
     216             :               "Source and destination accounts cannot be the same");
     217           2 :         }
     218             : 
     219         885 :         validator_.validateAccountId(reason, ta.srcAccountId());
     220         886 :         validator_.validateAccountId(reason, ta.destAccountId());
     221         889 :         validator_.validateAssetId(reason, ta.assetId());
     222         899 :         validator_.validateAmount(reason, ta.amount());
     223         897 :         validator_.validateDescription(reason, ta.description());
     224             : 
     225         906 :         return reason;
     226         906 :       }
     227             : 
     228             :      private:
     229             :       FieldValidator validator_;
     230       25056 :       mutable int command_counter{0};
     231             : 
     232             :       // adds command to a reason, appends and increments counter
     233             :       void addInvalidCommand(ReasonsGroupType &reason,
     234             :                              const std::string &command_name) const {
     235       25211 :         reason.first =
     236       24930 :             (boost::format("%d %s") % command_counter % command_name).str();
     237       25211 :         command_counter++;
     238       25211 :       }
     239             :     };
     240             : 
     241             :     /**
     242             :      * Class that validates commands from transaction
     243             :      * @tparam FieldValidator
     244             :      * @tparam CommandValidator
     245             :      */
     246             :     template <typename FieldValidator, typename CommandValidator>
     247             :     class TransactionValidator
     248             :         : public AbstractValidator<interface::Transaction> {
     249             :      private:
     250             :       template <typename CreatedTimeValidator>
     251             :       Answer validateImpl(const interface::Transaction &tx,
     252             :                           CreatedTimeValidator &&validator) const {
     253        9225 :         Answer answer;
     254        9225 :         std::string tx_reason_name = "Transaction";
     255        9263 :         ReasonsGroupType tx_reason(tx_reason_name, GroupedReasons());
     256             : 
     257        9547 :         if (tx.commands().empty()) {
     258           5 :           tx_reason.second.push_back(
     259           5 :               "Transaction should contain at least one command");
     260           5 :         }
     261             : 
     262        9289 :         field_validator_.validateCreatorAccountId(tx_reason,
     263        9289 :                                                   tx.creatorAccountId());
     264        9296 :         std::forward<CreatedTimeValidator>(validator)(tx_reason,
     265        9296 :                                                       tx.createdTime());
     266        9320 :         field_validator_.validateQuorum(tx_reason, tx.quorum());
     267        9438 :         if (tx.batchMeta() != boost::none)
     268         144 :           field_validator_.validateBatchMeta(tx_reason, **tx.batchMeta());
     269             : 
     270        9414 :         if (not tx_reason.second.empty()) {
     271          16 :           answer.addReason(std::move(tx_reason));
     272          16 :         }
     273             : 
     274       34473 :         for (const auto &command : tx.commands()) {
     275       25197 :           auto reason = boost::apply_visitor(CommandValidator(), command.get());
     276       25197 :           if (not reason.second.empty()) {
     277          65 :             answer.addReason(std::move(reason));
     278          65 :           }
     279       25020 :         }
     280             : 
     281        9532 :         return answer;
     282        9532 :       }
     283             : 
     284             :      public:
     285             :       explicit TransactionValidator(
     286             :           const FieldValidator &field_validator = FieldValidator())
     287        2147 :           : field_validator_(field_validator) {}
     288             : 
     289             :       /**
     290             :        * Applies validation to given transaction
     291             :        * @param tx - transaction to validate
     292             :        * @return Answer containing found error if any
     293             :        */
     294             :       Answer validate(const interface::Transaction &tx) const override {
     295             :         return validateImpl(tx, [this](auto &reason, auto time) {
     296        7830 :           field_validator_.validateCreatedTime(reason, time);
     297        7830 :         });
     298             :       }
     299             : 
     300             :       /**
     301             :        * Validates transaction against current_timestamp instead of time
     302             :        * provider
     303             :        */
     304             :       Answer validate(const interface::Transaction &tx,
     305             :                       interface::types::TimestampType current_timestamp) const {
     306        1602 :         return validateImpl(tx,
     307             :                             [this, current_timestamp](auto &reason, auto time) {
     308        1602 :                               field_validator_.validateCreatedTime(
     309        1602 :                                   reason, time, current_timestamp);
     310        1602 :                             });
     311             :       }
     312             : 
     313             :      protected:
     314             :       FieldValidator field_validator_;
     315             :     };
     316             : 
     317             :   }  // namespace validation
     318             : }  // namespace shared_model
     319             : 
     320             : #endif  // IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP

Generated by: LCOV version 1.13