hyperledger/iroha
Iroha - A simple, decentralized ledger http://iroha.tech
transaction_validator.hpp
Go to the documentation of this file.
1 
6 #ifndef IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP
7 #define IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP
8 
9 #include <boost/range/adaptor/indexed.hpp>
10 #include <boost/variant.hpp>
11 
12 #include "common/bind.hpp"
36 
37 namespace shared_model {
38  namespace validation {
39 
46  template <typename FieldValidator>
48  : public boost::static_visitor<boost::optional<ValidationError>> {
50  : validator_(std::move(validator)) {}
51 
52  public:
53  CommandValidatorVisitor(std::shared_ptr<ValidatorsConfig> config)
54  : CommandValidatorVisitor(FieldValidator{std::move(config)}) {}
55 
56  boost::optional<ValidationError> operator()(
57  const interface::AddAssetQuantity &add_asset_quantity) const {
58  return aggregateErrors(
59  "AddAssetQuantity",
60  {},
61  {validator_.validateAssetId(add_asset_quantity.assetId()),
62  validator_.validateAmount(add_asset_quantity.amount())});
63  }
64 
65  boost::optional<ValidationError> operator()(
66  const interface::AddPeer &add_peer) const {
67  return aggregateErrors(
68  "AddPeer", {}, {validator_.validatePeer(add_peer.peer())});
69  }
70 
71  boost::optional<ValidationError> operator()(
72  const interface::AddSignatory &add_signatory) const {
73  return aggregateErrors(
74  "AddSignatory",
75  {},
76  {validator_.validateAccountId(add_signatory.accountId()),
77  validator_.validatePubkey(add_signatory.pubkey())});
78  }
79 
80  boost::optional<ValidationError> operator()(
81  const interface::AppendRole &append_role) const {
82  return aggregateErrors(
83  "AppendRole",
84  {},
85  {validator_.validateAccountId(append_role.accountId()),
86  validator_.validateRoleId(append_role.roleName())});
87  }
88 
89  boost::optional<ValidationError> operator()(
90  const interface::CreateAccount &create_account) const {
91  return aggregateErrors(
92  "CreateAccount",
93  {},
94  {validator_.validatePubkey(create_account.pubkey()),
95  validator_.validateAccountName(create_account.accountName()),
96  validator_.validateDomainId(create_account.domainId())});
97  }
98 
99  boost::optional<ValidationError> operator()(
100  const interface::CreateAsset &create_asset) const {
101  return aggregateErrors(
102  "CreateAsset",
103  {},
104  {validator_.validateAssetName(create_asset.assetName()),
105  validator_.validateDomainId(create_asset.domainId()),
106  validator_.validatePrecision(create_asset.precision())});
107  }
108 
109  boost::optional<ValidationError> operator()(
110  const interface::CreateDomain &create_domain) const {
111  return aggregateErrors(
112  "CreateDomain",
113  {},
114  {validator_.validateDomainId(create_domain.domainId()),
115  validator_.validateRoleId(create_domain.userDefaultRole())});
116  }
117 
118  boost::optional<ValidationError> operator()(
119  const interface::CreateRole &create_role) const {
120  ValidationErrorCreator error_creator;
121  error_creator |= validator_.validateRoleId(create_role.roleName());
122 
123  create_role.rolePermissions().iterate([&error_creator, this](auto i) {
124  error_creator |= validator_.validateRolePermission(i);
125  });
126  return std::move(error_creator).getValidationError("CreateRole");
127  }
128 
129  boost::optional<ValidationError> operator()(
130  const interface::DetachRole &detach_role) const {
131  return aggregateErrors(
132  "DetachRole",
133  {},
134  {validator_.validateAccountId(detach_role.accountId()),
135  validator_.validateRoleId(detach_role.roleName())});
136  }
137 
138  boost::optional<ValidationError> operator()(
139  const interface::GrantPermission &grant_permission) const {
140  return aggregateErrors(
141  "GrantPermission",
142  {},
143  {validator_.validateAccountId(grant_permission.accountId()),
144  validator_.validateGrantablePermission(
145  grant_permission.permissionName())});
146  }
147 
148  boost::optional<ValidationError> operator()(
149  const interface::RemovePeer &remove_peer) const {
150  return aggregateErrors(
151  "RemovePeer",
152  {},
153  {validator_.validatePubkey(remove_peer.pubkey())});
154  }
155 
156  boost::optional<ValidationError> operator()(
157  const interface::RemoveSignatory &remove_signatory) const {
158  return aggregateErrors(
159  "RemoveSignatory",
160  {},
161  {validator_.validateAccountId(remove_signatory.accountId()),
162  validator_.validatePubkey(remove_signatory.pubkey())});
163  }
164 
165  boost::optional<ValidationError> operator()(
166  const interface::RevokePermission &revoke_permission) const {
167  return aggregateErrors(
168  "RevokePermission",
169  {},
170  {validator_.validateAccountId(revoke_permission.accountId()),
171  validator_.validateGrantablePermission(
172  revoke_permission.permissionName())});
173  }
174 
175  boost::optional<ValidationError> operator()(
176  const interface::SetAccountDetail &set_account_detail) const {
177  return aggregateErrors(
178  "SetAccountDetail",
179  {},
180  {validator_.validateAccountId(set_account_detail.accountId()),
181  validator_.validateAccountDetailKey(set_account_detail.key()),
182  validator_.validateAccountDetailValue(
183  set_account_detail.value())});
184  }
185 
186  boost::optional<ValidationError> operator()(
187  const interface::SetQuorum &set_quorum) const {
188  return aggregateErrors(
189  "SetQuorum",
190  {},
191  {validator_.validateAccountId(set_quorum.accountId()),
192  validator_.validateQuorum(set_quorum.newQuorum())});
193  }
194 
195  boost::optional<ValidationError> operator()(
196  const interface::SubtractAssetQuantity &subtract_asset_quantity)
197  const {
198  return aggregateErrors(
199  "SubtractAssetQuantity",
200  {},
201  {validator_.validateAssetId(subtract_asset_quantity.assetId()),
202  validator_.validateAmount(subtract_asset_quantity.amount())});
203  }
204 
205  boost::optional<ValidationError> operator()(
206  const interface::TransferAsset &transfer_asset) const {
207  return aggregateErrors(
208  "TransferAsset",
209  {[&]() -> boost::optional<std::string> {
210  if (transfer_asset.srcAccountId()
211  == transfer_asset.destAccountId()) {
212  return std::string{
213  "Source and destination accounts are the same."};
214  }
215  return boost::none;
216  }()},
217  {validator_.validateAccountId(transfer_asset.srcAccountId()),
218  validator_.validateAccountId(transfer_asset.destAccountId()),
219  validator_.validateAssetId(transfer_asset.assetId()),
220  validator_.validateAmount(transfer_asset.amount()),
221  validator_.validateDescription(transfer_asset.description())});
222  }
223 
224  boost::optional<ValidationError> operator()(
226  &compare_and_set_account_detail) const {
227  using iroha::operator|;
228  return aggregateErrors(
229  "CompareAndSetAccountDetail",
230  {},
231  {validator_.validateAccountId(
232  compare_and_set_account_detail.accountId()),
233  validator_.validateAccountDetailKey(
234  compare_and_set_account_detail.key()),
235  validator_.validateAccountDetailValue(
236  compare_and_set_account_detail.value()),
237  compare_and_set_account_detail.oldValue() |
238  [this](
239  const auto &oldValue) -> boost::optional<ValidationError> {
240  return this->validator_.validateOldAccountDetailValue(oldValue);
241  }});
242  }
243 
244  boost::optional<ValidationError> operator()(
245  const interface::SetSettingValue &set_setting_value) const {
246  // genesis block does not undergo stateless validation
247  return ValidationError(
248  "SetSettingValue",
249  {"The command can only be called from genesis block"});
250  }
251 
252  private:
253  FieldValidator validator_;
254  };
255 
261  template <typename FieldValidator, typename CommandValidator>
263  : public AbstractValidator<interface::Transaction> {
264  private:
265  template <typename CreatedTimeValidator>
266  boost::optional<ValidationError> validateImpl(
267  const interface::Transaction &tx,
268  CreatedTimeValidator &&validator) const {
269  using iroha::operator|;
270 
271  ValidationErrorCreator error_creator;
272 
273  if (tx.commands().empty()) {
274  error_creator.addReason(
275  "Transaction must contain at least one command.");
276  }
277 
278  error_creator |=
279  field_validator_.validateCreatorAccountId(tx.creatorAccountId());
280  error_creator |=
281  std::forward<CreatedTimeValidator>(validator)(tx.createdTime());
282  error_creator |= field_validator_.validateQuorum(tx.quorum());
283  error_creator |= tx.batchMeta() | [this](const auto &batch_meta) {
284  return field_validator_.validateBatchMeta(*batch_meta);
285  };
286 
287  for (const auto &cmd : tx.commands() | boost::adaptors::indexed(1)) {
288  boost::apply_visitor(command_validator_visitor_, cmd.value().get()) |
289  [&cmd, &error_creator](auto error) {
290  error_creator.addChildError(ValidationError{
291  std::string{"Command #"} + std::to_string(cmd.index()),
292  {},
293  {error}});
294  };
295  }
296 
297  return std::move(error_creator).getValidationError("Transaction");
298  }
299 
300  public:
302  const std::shared_ptr<ValidatorsConfig> &config)
303  : field_validator_(config), command_validator_visitor_(config) {}
304 
310  boost::optional<ValidationError> validate(
311  const interface::Transaction &tx) const override {
312  return validateImpl(tx, [this](auto time) {
313  return field_validator_.validateCreatedTime(time);
314  });
315  }
316 
321  boost::optional<ValidationError> validate(
322  const interface::Transaction &tx,
323  interface::types::TimestampType current_timestamp) const {
324  return validateImpl(tx, [this, current_timestamp](auto time) {
325  return field_validator_.validateCreatedTime(time, current_timestamp);
326  });
327  }
328 
329  protected:
331  CommandValidator command_validator_visitor_;
332  };
333 
334  } // namespace validation
335 } // namespace shared_model
336 
337 #endif // IROHA_SHARED_MODEL_TRANSACTION_VALIDATOR_HPP
Definition: compare_and_set_account_detail.hpp:21
virtual const types::AccountIdType & accountId() const =0
virtual const types::RoleIdType & roleName() const =0
boost::optional< ValidationError > operator()(const interface::TransferAsset &transfer_asset) const
Definition: transaction_validator.hpp:205
Definition: add_signatory.hpp:19
virtual const types::AccountIdType & srcAccountId() const =0
virtual const interface::types::PubkeyType & pubkey() const =0
ValidationErrorCreator & addChildError(ValidationError error)
Add a child error.
Definition: validation_error_helpers.cpp:28
boost::optional< ValidationError > validateAssetName(const interface::types::AssetNameType &asset_name) const
Definition: field_validator.cpp:186
boost::optional< ValidationError > validateAssetId(const interface::types::AssetIdType &asset_id) const
Definition: field_validator.cpp:131
boost::optional< ValidationError > operator()(const interface::RevokePermission &revoke_permission) const
Definition: transaction_validator.hpp:165
virtual const interface::Peer & peer() const =0
boost::optional< ValidationError > validateAccountId(const interface::types::AccountIdType &account_id) const
Definition: field_validator.cpp:126
Represents a validation error.
Definition: validation_error.hpp:19
boost::optional< ValidationError > validatePubkey(const interface::types::PubkeyType &pubkey) const
Definition: field_validator.cpp:153
virtual const types::AccountIdType & destAccountId() const =0
boost::optional< ValidationError > validateQuorum(const interface::types::QuorumType &quorum) const
Definition: field_validator.cpp:243
virtual types::QuorumType quorum() const =0
Definition: set_quorum.hpp:18
virtual const types::AccountIdType & accountId() const =0
Definition: subtract_asset_quantity.hpp:20
virtual const types::AccountDetailValueType & value() const =0
TransactionValidator(const std::shared_ptr< ValidatorsConfig > &config)
Definition: transaction_validator.hpp:301
Definition: abstract_validator.hpp:17
Definition: set_setting_value.hpp:19
boost::optional< ValidationError > operator()(const interface::AppendRole &append_role) const
Definition: transaction_validator.hpp:80
boost::optional< ValidationError > operator()(const interface::CreateDomain &create_domain) const
Definition: transaction_validator.hpp:109
boost::optional< ValidationError > getValidationError(const ReasonName &name) &&
Definition: validation_error_helpers.cpp:15
virtual const types::AccountIdType & accountId() const =0
boost::optional< ValidationError > validateRolePermission(const interface::permissions::Role &permission) const
Definition: field_validator.cpp:223
Definition: detach_role.hpp:19
virtual const types::AccountIdType & accountId() const =0
Definition: remove_signatory.hpp:18
Definition: create_asset.hpp:18
virtual const Amount & amount() const =0
boost::optional< ValidationError > validateGrantablePermission(const interface::permissions::Grantable &permission) const
Definition: field_validator.cpp:233
virtual const types::AssetIdType & assetId() const =0
boost::optional< ValidationError > operator()(const interface::SetQuorum &set_quorum) const
Definition: transaction_validator.hpp:186
boost::optional< ValidationError > operator()(const interface::AddSignatory &add_signatory) const
Definition: transaction_validator.hpp:71
Definition: remove_peer.hpp:20
virtual const RolePermissionSet & rolePermissions() const =0
virtual const types::AccountIdType & accountId() const =0
Definition: append_role.hpp:19
boost::optional< ValidationError > validateAccountName(const interface::types::AccountNameType &account_name) const
Definition: field_validator.cpp:168
Definition: transfer_asset.hpp:19
virtual types::TimestampType createdTime() const =0
virtual const types::AssetIdType & assetId() const =0
ValidationErrorCreator & addReason(ReasonType reason)
Add a reason to error.
Definition: validation_error_helpers.cpp:23
virtual const types::AccountNameType & accountName() const =0
boost::optional< ValidationError > operator()(const interface::AddAssetQuantity &add_asset_quantity) const
Definition: transaction_validator.hpp:56
virtual const types::RoleIdType & roleName() const =0
boost::optional< ValidationError > validateAmount(const interface::Amount &amount) const
Definition: field_validator.cpp:144
virtual const types::AccountIdType & accountId() const =0
virtual const PrecisionType & precision() const =0
boost::optional< ValidationError > validateOldAccountDetailValue(const boost::optional< interface::types::AccountDetailValueType > &old_value) const
Definition: field_validator.cpp:209
virtual const types::AccountDetailValueType & value() const =0
virtual const types::RoleIdType & roleName() const =0
virtual const Amount & amount() const =0
virtual const types::AccountDetailKeyType & key() const =0
Definition: create_domain.hpp:18
virtual types::QuorumType newQuorum() const =0
virtual permissions::Grantable permissionName() const =0
Definition: create_account.hpp:19
boost::optional< ValidationError > operator()(const interface::CreateRole &create_role) const
Definition: transaction_validator.hpp:118
virtual const types::PubkeyType & pubkey() const =0
virtual const types::DomainIdType & domainId() const =0
virtual const boost::optional< types::AccountDetailValueType > oldValue() const =0
Definition: grant_permission.hpp:19
boost::optional< ValidationError > operator()(const interface::DetachRole &detach_role) const
Definition: transaction_validator.hpp:129
virtual const types::RoleIdType & userDefaultRole() const =0
boost::optional< ValidationError > validatePeer(const interface::Peer &peer) const
Definition: field_validator.cpp:136
boost::optional< ValidationError > operator()(const interface::RemovePeer &remove_peer) const
Definition: transaction_validator.hpp:148
boost::optional< ValidationError > validateRoleId(const interface::types::RoleIdType &role_id) const
Definition: field_validator.cpp:163
Definition: set_account_detail.hpp:19
virtual const types::AccountDetailKeyType & key() const =0
boost::optional< ValidationError > operator()(const interface::SubtractAssetQuantity &subtract_asset_quantity) const
Definition: transaction_validator.hpp:195
virtual CommandsType commands() const =0
boost::optional< ValidationError > validatePrecision(const interface::types::PrecisionType &precision) const
Definition: field_validator.cpp:218
Definition: field_validator.hpp:40
virtual const types::AssetNameType & assetName() const =0
Definition: revoke_permission.hpp:19
virtual const types::DescriptionType & description() const =0
virtual const types::AccountIdType & accountId() const =0
Definition: transaction_validator.hpp:47
boost::optional< ValidationError > operator()(const interface::CreateAsset &create_asset) const
Definition: transaction_validator.hpp:99
CommandValidator command_validator_visitor_
Definition: transaction_validator.hpp:331
Helper class for ValidationError creation.
Definition: validation_error_helpers.hpp:16
Definition: transaction_validator.hpp:262
void iterate(std::function< void(Perm)> f) const
Definition: permissions.cpp:138
boost::optional< ValidationError > operator()(const interface::SetAccountDetail &set_account_detail) const
Definition: transaction_validator.hpp:175
boost::optional< ValidationError > operator()(const interface::AddPeer &add_peer) const
Definition: transaction_validator.hpp:65
boost::optional< ValidationError > operator()(const interface::CompareAndSetAccountDetail &compare_and_set_account_detail) const
Definition: transaction_validator.hpp:224
boost::optional< ValidationError > aggregateErrors(const ReasonName &name, std::vector< boost::optional< ReasonType >> optional_reasons, std::vector< boost::optional< ValidationError >> optional_child_errors)
Definition: validation_error_helpers.cpp:57
virtual const types::AccountIdType & accountId() const =0
Definition: add_asset_quantity.hpp:20
virtual boost::optional< std::shared_ptr< BatchMeta > > batchMeta() const =0
virtual const Amount & amount() const =0
virtual const types::DomainIdType & domainId() const =0
virtual const types::PubkeyType & pubkey() const =0
Definition: create_role.hpp:19
boost::optional< ValidationError > validate(const interface::Transaction &tx, interface::types::TimestampType current_timestamp) const
Definition: transaction_validator.hpp:321
virtual const types::AccountIdType & creatorAccountId() const =0
Definition: command_executor.hpp:12
boost::optional< ValidationError > validateAccountDetailValue(const interface::types::AccountDetailValueType &value) const
Definition: field_validator.cpp:196
FieldValidator field_validator_
Definition: transaction_validator.hpp:330
boost::optional< ValidationError > validate(const interface::Transaction &tx) const override
Definition: transaction_validator.hpp:310
virtual permissions::Grantable permissionName() const =0
boost::optional< ValidationError > validateDomainId(const interface::types::DomainIdType &domain_id) const
Definition: field_validator.cpp:173
virtual const types::AccountIdType & accountId() const =0
Definition: transaction.hpp:23
virtual const types::DomainIdType & domainId() const =0
boost::optional< ValidationError > validateDescription(const interface::types::DescriptionType &description) const
Definition: field_validator.cpp:345
Definition: add_peer.hpp:20
CommandValidatorVisitor(std::shared_ptr< ValidatorsConfig > config)
Definition: transaction_validator.hpp:53
boost::optional< ValidationError > validateAccountDetailKey(const interface::types::AccountDetailKeyType &key) const
Definition: field_validator.cpp:191
boost::optional< ValidationError > operator()(const interface::CreateAccount &create_account) const
Definition: transaction_validator.hpp:89
boost::optional< ValidationError > operator()(const interface::SetSettingValue &set_setting_value) const
Definition: transaction_validator.hpp:244
uint64_t TimestampType
Type of timestamp.
Definition: types.hpp:64
virtual const types::PubkeyType & pubkey() const =0
virtual const types::AssetIdType & assetId() const =0
boost::optional< ValidationError > operator()(const interface::RemoveSignatory &remove_signatory) const
Definition: transaction_validator.hpp:156
boost::optional< ValidationError > operator()(const interface::GrantPermission &grant_permission) const
Definition: transaction_validator.hpp:138