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