BitShares-Core  5.0.0
BitShares blockchain implementation and command-line interface software
restriction_predicate.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
26 
28 
29 #include "safe_compare.hpp"
30 
31 namespace graphene { namespace protocol {
32 namespace typelist = fc::typelist;
33 using std::declval;
34 using std::size_t;
37 
38 // Make our own std::void_t since the real one isn't available in C++14
39 template<typename...> using make_void = void;
40 
41 // Metafunction to check if type is some instantiation of fc::safe
42 template<typename> constexpr static bool is_safe = false;
43 template<typename I> constexpr static bool is_safe<fc::safe<I>> = true;
44 
45 // Metafunction to check if type is a flat_set of any element type
46 template<typename> struct is_flat_set_impl : std::false_type {};
47 template<typename T> struct is_flat_set_impl<flat_set<T>> : std::true_type {};
48 template<typename T> constexpr static bool is_flat_set = is_flat_set_impl<T>::value;
49 
50 // We use our own is_integral which does not consider bools integral (to disallow comparison between bool and ints)
51 template<typename T> constexpr static bool is_integral = !std::is_same<T, bool>::value &&
52  !std::is_same<T, safe<bool>>::value &&
53  (is_safe<T> || std::is_integral<T>::value);
54 
55 // Metafunction to check if two types are comparable, which means not void_t, and either the same or both integral
56 template<typename T, typename U>
57 constexpr static bool comparable_types = !std::is_same<T, void_t>::value &&
58  (std::is_same<T, U>::value || (is_integral<T> && is_integral<U>));
59 
60 // Metafunction to check if type is a container
61 template<typename, typename = void>
62 struct is_container_impl : std::false_type {};
63 template<typename T>
64 struct is_container_impl<T, make_void<typename T::value_type, decltype(declval<T>().size())>> : std::true_type {};
65 template<typename T> constexpr static bool is_container = is_container_impl<T>::value;
66 
67 // Type alias for a predicate on a particular field type
68 template<typename Field>
69 using object_restriction_predicate = std::function<predicate_result(const Field&)>;
70 
71 // Get the actual number when type might be a safe<I>
72 template<typename I, typename=std::enable_if_t<std::is_integral<I>::value>>
73 const auto& to_num(const I& i) { return i; }
74 template<typename I>
75 const auto& to_num(const fc::safe<I>& i) { return i.value; }
76 inline auto to_num(const fc::time_point_sec& t) { return t.sec_since_epoch(); }
77 
79 
81 // *** Restriction Predicate Logic ***
82 //
83 // This file implements the core logic of Custom Active Authorities. A CAA is an authority which is permitted by an
84 // account to execute a particular authority on that account's behalf, with some restrictions on the content of that
85 // operation. This file implements the logic to validate those restrictions, and create a predicate function which
86 // takes a particular operation and determines whether it complies with the restrictions or not.
87 //
88 // The restrictions are a recursive structure, which applies to a particular operation struct, but may recurse to
89 // specify restrictions on fields or subfields of that struct. This file explores the restriction structure in tandem
90 // with the operation struct to verify that all of the restrictions are valid and to produce a predicate function.
91 // Note that this file operates primarily on restriction data, but only operation *types*, meaning the actual
92 // operation value does not appear until the predicate returned by this file is run.
93 //
94 // As a result, this file is very template heavy, and does a good deal of type manipulation. Its contents are
95 // organized as a series of layers, which recursively examine the restrictions and types they apply to, and finally,
96 // once all the types have been resolved, a predicate function is created which evaluates the restrictions on an
97 // operation.
98 //
99 // To give an overview of the logic, the layers stack up like so, from beginning (bottom of file) to end:
100 // - restrictions_to_predicate<Object>() -- takes a vector<restriction> and creates a predicate for each of them,
101 // but returns a single predicate that returns true only if all sub-predicates return true
102 // - create_field_predicate<Object>() -- Resolves which field of Object the restriction is referencing by indexing
103 // into the object's reflected fields with the predicate's member_index
104 // - create_logical_or_predicate<Object>() -- If the predicate is a logical OR function, the predicate does not
105 // specify a field to examine; rather, the predicates in its branches do. Thus this function recurses into
106 // restrictions_to_predicate for each branch of the OR, and combines the resulting predicates in a predicate
107 // which returns true if any branch of the OR passes
108 // - create_predicate_function<Field>() -- switches on restriction type to determine which predicate template to use
109 // going forward
110 // - make_predicate<Predicate, Field, ArgVariant> -- Determines what type the restriction argument is and creates
111 // a predicate functor for that type
112 // - attribute_assertion<Field> -- If the restriction is an attribute assertion, instead of using make_predicate
113 // to create a predicate function, we first recurse into restrictions_to_predicate with Field as the Object
114 // - variant_assertion<Field> -- If the restriction is a variant assertion, instead of using make_predicate, we
115 // recurse into restrictions_to_predicate with the variant value as the Object
116 // - embed_argument<Field, Predicate, Argument>() -- Embeds the argument into the predicate if it is a valid type
117 // for the predicate, and throws otherwise.
118 // - predicate_xyz<Argument> -- These are functors implementing the various predicate function types
120 
121 // These typelists contain the argument types legal for various function types:
122 
123 // Valid for magnitude comparisons and equality comparisons
124 using comparable_types_list = typelist::list<int64_t, string, time_point_sec, account_id_type, asset_id_type,
125  force_settlement_id_type, committee_member_id_type, witness_id_type,
126  limit_order_id_type, call_order_id_type, custom_id_type,
127  proposal_id_type, withdraw_permission_id_type,
128  vesting_balance_id_type, worker_id_type, balance_id_type>;
129 // Valid for list functions (in, not_in, has_all, has_none)
130 struct make_flat_set { template<typename T> struct transform { using type = flat_set<T>; }; };
134 // Valid for equality comparisons but not necessarily magnitude comparisons
137 // Valid for attritube assertions
139 // Valid for logical or assertions
141 
143 // An invalid predicate which throws upon construction. Inherited by other predicates when arg types are incompatible
144 template<typename A, typename B>
146  constexpr static bool valid = false;
147  predicate_invalid() { FC_THROW_EXCEPTION(fc::assert_exception, "Invalid types for predicate"); }
148  bool operator()(const A&, const B&) const { return false; }
149 };
150 // Equality comparison
151 template<typename A, typename B, typename = void> struct predicate_eq : predicate_invalid<A, B> {};
152 template<typename Field, typename Argument>
153 struct predicate_eq<Field, Argument, std::enable_if_t<std::is_same<Field, Argument>::value>> {
154  // Simple comparison, same type
155  constexpr static bool valid = true;
156  constexpr bool operator()(const Field& f, const Argument& a) const { return f == a; }
157 };
158 template<typename Field, typename Argument>
159 struct predicate_eq<Field, Argument, std::enable_if_t<is_integral<Field> && is_integral<Argument> &&
160  !std::is_same<Field, Argument>::value>> {
161  // Simple comparison, integral types
162  constexpr static bool valid = true;
163  constexpr bool operator()(const Field& f, const Argument& a) const { return safenum::equal(to_num(f), to_num(a)); }
164 };
165 template<typename Field, typename Argument>
166 struct predicate_eq<Field, Argument, std::enable_if_t<is_container<Field> && is_integral<Argument>>> {
167  // Compare container size against int
168  constexpr static bool valid = true;
169  bool operator()(const Field& f, const Argument& a) const { return safenum::equal(f.size(), to_num(a)); }
170 };
171 template<typename Field, typename Argument>
172 struct predicate_eq<fc::optional<Field>, Argument, std::enable_if_t<comparable_types<Field, Argument>>>
173  : predicate_eq<Field, Argument> {
174  // Compare optional value against comparable type
176  bool operator()(const fc::optional<Field>& f, const Argument& a) const {
178  return (*this)(*f, a);
179  }
180 };
181 template<typename Field>
182 struct predicate_eq<fc::optional<Field>, void_t, void> {
183  // Compare optional value against void_t (checks that optional is null)
184  constexpr static bool valid = true;
185  bool operator()(const fc::optional<Field>& f, const void_t&) const { return !f.valid(); }
186 };
187 // Not-equal is just an equality comparison wrapped in a negator
188 template<typename Field, typename Argument> struct predicate_ne : predicate_eq<Field, Argument> {
190  bool operator()(const Field& f, const Argument& a) const { return !equal::operator()(f, a); }
191 };
192 
193 // Shared implementation for all inequality comparisons
194 template<typename A, typename B, typename = void> struct predicate_compare : predicate_invalid<A, B> {};
195 template<typename Field, typename Argument>
196 struct predicate_compare<Field, Argument, std::enable_if_t<std::is_same<Field, Argument>::value>> {
197  // Simple comparison, same types
198  constexpr static bool valid = true;
199  constexpr int8_t operator()(const Field& f, const Argument& a) const {
200  return f<a? -1 : (f>a? 1 : 0);
201  }
202 };
203 template<typename Field, typename Argument>
204 struct predicate_compare<Field, Argument, std::enable_if_t<is_integral<Field> && is_integral<Argument> &&
205  !std::is_same<Field, Argument>::value>> {
206  // Simple comparison, integral types
207  constexpr static bool valid = true;
208  constexpr int8_t operator()(const Field& f, const Argument& a) const {
209  auto nf = to_num(f);
210  auto na = to_num(a);
211  return safenum::less_than(nf, na)? -1 : (safenum::greater_than(nf, na)? 1 : 0);
212  }
213 };
214 template<typename Field, typename Argument>
215 struct predicate_compare<fc::optional<Field>, Argument, void> : predicate_compare<Field, Argument> {
216  // Compare optional value against comparable type
217  constexpr static bool valid = true;
218  constexpr int8_t operator()(const fc::optional<Field>& f, const Argument& a) const {
220  return (*this)(*f, a);
221  }
222 };
223 // The actual inequality predicates
224 template<typename Field, typename Argument> struct predicate_lt : predicate_compare<Field, Argument> {
226  constexpr bool operator()(const Field& f, const Argument& a) const { return base::operator()(f, a) < 0; }
227 };
228 template<typename Field, typename Argument> struct predicate_le : predicate_compare<Field, Argument> {
230  constexpr bool operator()(const Field& f, const Argument& a) const { return base::operator()(f, a) <= 0; }
231 };
232 template<typename Field, typename Argument> struct predicate_gt : predicate_compare<Field, Argument> {
234  constexpr bool operator()(const Field& f, const Argument& a) const { return base::operator()(f, a) > 0; }
235 };
236 template<typename Field, typename Argument> struct predicate_ge : predicate_compare<Field, Argument> {
238  constexpr bool operator()(const Field& f, const Argument& a) const { return base::operator()(f, a) >= 0; }
239 };
240 
241 // Field-in-list predicate
242 template<typename F, typename C, typename = void> struct predicate_in : predicate_invalid<F, C> {};
243 template<typename Field, typename Element>
244 struct predicate_in<Field, flat_set<Element>, std::enable_if_t<comparable_types<Field, Element> && !is_safe<Field>>> {
245  // Simple inclusion check
246  constexpr static bool valid = true;
247  bool operator()(const Field& f, const flat_set<Element>& c) const { return c.count(f) != 0; }
248 };
249 template<typename Field, typename Element>
250 struct predicate_in<fc::safe<Field>, flat_set<Element>, std::enable_if_t<comparable_types<Field, Element>>> {
251  // Check for safe value
252  constexpr static bool valid = true;
253  bool operator()(const fc::safe<Field>& f, const flat_set<Element>& c) const { return c.count(f.value) != 0; }
254 };
255 template<typename Field, typename Element>
256 struct predicate_in<fc::optional<Field>, flat_set<Element>, std::enable_if_t<comparable_types<Field, Element>>> {
257  // Check for optional value
258  constexpr static bool valid = true;
259  bool operator()(const fc::optional<Field>& f, const flat_set<Element>& c) const {
261  return c.count(*f) != 0;
262  }
263 };
264 template<typename Container, typename Element>
265 struct predicate_in<Container, flat_set<Element>,
266  std::enable_if_t<is_container<Container> &&
267  comparable_types<typename Container::value_type, Element>>> {
268  // Check all values in container are in argument
269  constexpr static bool valid = true;
270  // Unsorted container
271  template<typename C = Container, std::enable_if_t<!is_flat_set<C>, bool> = true>
272  bool operator()(const Container& c, const flat_set<Element>& a) const {
273  return std::all_of(c.begin(), c.end(), [&a](const auto& ce) { return a.count(ce) > 0; });
274  }
275  // Sorted container
276  template<typename C = Container, std::enable_if_t<is_flat_set<C>, bool> = true>
277  bool operator()(const Container& c, const flat_set<Element>& a) const {
278  return std::includes(a.begin(), a.end(), c.begin(), c.end());
279  }
280 };
281 // Field-not-in-list is just field-in-list wrapped in a negator
282 template<typename Field, typename Container, typename=void> struct predicate_not_in : predicate_in<Field, Container> {
284  bool operator()(const Field& f, const Container& c) const { return !base::operator()(f, c); }
285 };
286 // Container-field-not-in-list is not a simple negation of predicate_in, specialize here
287 template<typename Container, typename Element>
288 struct predicate_not_in<Container, flat_set<Element>,
289  std::enable_if_t<is_container<Container> &&
290  comparable_types<typename Container::value_type, Element>>> {
291  constexpr static bool valid = true;
292  // Unsorted container
293  template<typename C = Container, std::enable_if_t<!is_flat_set<C>, bool> = true>
294  bool operator()(const Container& c, const flat_set<Element>& a) const {
295  return std::none_of(c.begin(), c.end(), [&a](const auto& ce) { return a.count(ce) > 0; });
296  }
297  // Sorted container
298  template<typename C = Container, std::enable_if_t<is_flat_set<C>, bool> = true>
299  bool operator()(const Container& c, const flat_set<Element>& a) const {
300  flat_set<typename Container::value_type> intersection;
301  std::set_intersection(c.begin(), c.end(), a.begin(), a.end(),
302  std::inserter(intersection, intersection.begin()));
303  return intersection.empty();
304  }
305 };
306 
307 // List-contains-list predicate
308 template<typename C1, typename C2, typename = void> struct predicate_has_all : predicate_invalid<C1, C2> {};
309 template<typename FieldElement, typename ArgumentElement>
310 struct predicate_has_all<flat_set<FieldElement>, flat_set<ArgumentElement>,
311  std::enable_if_t<comparable_types<FieldElement, ArgumentElement>>> {
312  // Field is already flat_set
313  constexpr static bool valid = true;
314  bool operator()(const flat_set<FieldElement>& f, const flat_set<ArgumentElement>& a) const {
315  if (f.size() < a.size()) return false;
316  return std::includes(f.begin(), f.end(), a.begin(), a.end());
317  }
318 };
319 template<typename FieldContainer, typename ArgumentElement>
320 struct predicate_has_all<FieldContainer, flat_set<ArgumentElement>,
321  std::enable_if_t<is_container<FieldContainer> && !is_flat_set<FieldContainer> &&
322  comparable_types<typename FieldContainer::value_type, ArgumentElement>>> {
323  // Field is other container; convert to flat_set
324  constexpr static bool valid = true;
325  bool operator()(const FieldContainer& f, const flat_set<ArgumentElement>& a) const {
326  if (f.size() < a.size()) return false;
327  std::set<typename FieldContainer::value_type> fs(f.begin(), f.end());
328  return std::includes(fs.begin(), fs.end(), a.begin(), a.end());
329  }
330 };
331 template<typename OptionalType, typename Argument>
332 struct predicate_has_all<fc::optional<OptionalType>, Argument, void> : predicate_has_all<OptionalType, Argument> {
333  // Field is optional container
334  bool operator()(const fc::optional<OptionalType>& f, const Argument& a) const {
336  return (*this)(*f, a);
337  }
338 };
339 
340 // List contains none of list predicate
341 template<typename C1, typename C2, typename = void> struct predicate_has_none : predicate_invalid<C1, C2> {};
342 template<typename FieldElement, typename ArgumentElement>
343 struct predicate_has_none<flat_set<FieldElement>, flat_set<ArgumentElement>,
344  std::enable_if_t<comparable_types<FieldElement, ArgumentElement>>> {
345  // Field is already flat_set
346  constexpr static bool valid = true;
347  bool operator()(const flat_set<FieldElement>& f, const flat_set<ArgumentElement>& a) const {
348  flat_set<FieldElement> intersection;
349  std::set_intersection(f.begin(), f.end(), a.begin(), a.end(),
350  std::inserter(intersection, intersection.begin()));
351  return intersection.empty();
352  }
353 };
354 template<typename FieldContainer, typename ArgumentElement>
355 struct predicate_has_none<FieldContainer, flat_set<ArgumentElement>,
356  std::enable_if_t<is_container<FieldContainer> && !is_flat_set<FieldContainer> &&
357  comparable_types<typename FieldContainer::value_type, ArgumentElement>>> {
358  // Field is other container
359  constexpr static bool valid = true;
360  bool operator()(const FieldContainer& f, const flat_set<ArgumentElement>& a) const {
361  return !std::any_of(f.begin(), f.end(), [&a](const auto& fe) { return a.count(fe) > 0; });
362  }
363 };
364 template<typename OptionalType, typename Argument>
365 struct predicate_has_none<fc::optional<OptionalType>, Argument, void> : predicate_has_all<OptionalType, Argument> {
366  // Field is optional container
367  bool operator()(const fc::optional<OptionalType>& f, const Argument& a) const {
369  return (*this)(*f, a);
370  }
371 };
373 
374 // Forward declaration of restrictions_to_predicate, because attribute assertions and logical ORs recurse into it
375 template<typename Object> object_restriction_predicate<Object> restrictions_to_predicate(vector<restriction>, bool);
376 
377 template<typename Field>
379  static object_restriction_predicate<Field> create(vector<restriction>&& rs) {
380  return restrictions_to_predicate<Field>(std::move(rs), false);
381  }
382 };
383 template<typename Field>
384 struct attribute_assertion<fc::optional<Field>> {
385  static object_restriction_predicate<fc::optional<Field>> create(vector<restriction>&& rs) {
386  return [p=restrictions_to_predicate<Field>(std::move(rs), false)](const fc::optional<Field>& f) {
388  return p(*f);
389  };
390  }
391 };
392 template<typename Extension>
393 struct attribute_assertion<extension<Extension>> {
394  static object_restriction_predicate<extension<Extension>> create(vector<restriction>&& rs) {
395  return [p=restrictions_to_predicate<Extension>(std::move(rs), false)](const extension<Extension>& x) {
396  return p(x.value);
397  };
398  }
399 };
400 
401 template<typename Variant>
404  FC_THROW_EXCEPTION(fc::assert_exception, "Invalid variant assertion on non-variant field",
405  ("Field", fc::get_typename<Variant>::name()));
406  }
407 };
408 template<typename... Types>
410  using Variant = static_variant<Types...>;
411 
412  template<typename Value>
413  static auto make_predicate(vector<restriction>&& rs) {
414  return [p=restrictions_to_predicate<Value>(std::move(rs), true)](const Variant& v) {
415  if (v.which() == Variant::template tag<Value>::value)
416  return p(v.template get<Value>());
418  };
419  }
422  [&arg](auto t) -> object_restriction_predicate<Variant> {
423  using Value = typename decltype(t)::type;
424  return variant_assertion::make_predicate<Value>(std::move(arg.second));
425  });
426  }
427 };
428 template<typename... Types>
429 struct variant_assertion<fc::optional<static_variant<Types...>>> {
430  using Variant = static_variant<Types...>;
434  [&arg](auto t) -> object_restriction_predicate<Optional> {
435  using Value = typename decltype(t)::type;
436  auto pred = variant_assertion<Variant>::template make_predicate<Value>(std::move(arg.second));
437  return [p=std::move(pred)](const Optional& opt) {
438  if (!opt.valid()) return predicate_result::Rejection(predicate_result::null_optional);
439  return p(*opt);
440  };
441  });
442  }
443 };
444 
445 // Embed the argument into the predicate functor
446 template<typename F, typename P, typename A, typename = std::enable_if_t<P::valid>>
448  return [p=std::move(p), a=std::move(a)](const F& f) {
449  if (p(f, a)) return predicate_result::Success();
451  };
452 }
453 template<typename F, typename P, typename A>
455  FC_THROW_EXCEPTION(fc::assert_exception, "Invalid types for predicate");
456 }
457 
458 // Resolve the argument type and make a predicate for it
459 template<template<typename...> class Predicate, typename Field, typename ArgVariant>
461  return typelist::runtime::dispatch(typename ArgVariant::list(), arg.which(),
462  [&arg](auto t) mutable -> object_restriction_predicate<Field> {
463  using Arg = typename decltype(t)::type;
464  return embed_argument<Field>(Predicate<Field, Arg>(), std::move(arg.template get<Arg>()), short());
465  });
466 }
467 
468 template<typename Field>
470  try {
471  switch(func) {
473  return make_predicate<predicate_eq, Field>(static_variant<equality_types_list>::import_from(std::move(arg)));
475  return make_predicate<predicate_ne, Field>(static_variant<equality_types_list>::import_from(std::move(arg)));
477  return make_predicate<predicate_lt, Field>(static_variant<comparable_types_list>
478  ::import_from(std::move(arg)));
480  return make_predicate<predicate_le, Field>(static_variant<comparable_types_list>
481  ::import_from(std::move(arg)));
483  return make_predicate<predicate_gt, Field>(static_variant<comparable_types_list>
484  ::import_from(std::move(arg)));
486  return make_predicate<predicate_ge, Field>(static_variant<comparable_types_list>
487  ::import_from(std::move(arg)));
489  return make_predicate<predicate_in, Field>(static_variant<list_types_list>::import_from(std::move(arg)));
491  return make_predicate<predicate_not_in, Field>(static_variant<list_types_list>
492  ::import_from(std::move(arg)));
494  return make_predicate<predicate_has_all, Field>(static_variant<list_types_list>
495  ::import_from(std::move(arg)));
497  return make_predicate<predicate_has_none, Field>(static_variant<list_types_list>
498  ::import_from(std::move(arg)));
500  FC_ASSERT(arg.which() == restriction_argument::tag<vector<restriction>>::value,
501  "Argument type for attribute assertion must be restriction list");
502  return attribute_assertion<Field>::create(std::move(arg.get<vector<restriction>>()));
504  FC_ASSERT(arg.which() == restriction_argument::tag<restriction::variant_assert_argument_type>::value,
505  "Argument type for attribute assertion must be pair of variant tag and restriction list");
507  default:
508  FC_THROW_EXCEPTION(fc::assert_exception, "Invalid function type on restriction");
509  }
511 }
512 
513 #include "create_predicate_fwd.hxx"
514 
524 template<typename Object,
525  typename = std::enable_if_t<typelist::length<typename fc::reflector<Object>::native_members>() != 0>>
527  using member_list = typename fc::reflector<Object>::native_members;
528  FC_ASSERT( r.member_index < static_cast<uint64_t>(typelist::length<member_list>()),
529  "Invalid member index ${I} for object ${O}",
530  ("I", r.member_index)("O", fc::get_typename<Object>::name()) );
531  auto predicator = [f=r.restriction_type, a=std::move(r.argument)](auto t) -> object_restriction_predicate<Object> {
532  using FieldReflection = typename decltype(t)::type;
533  using Field = typename FieldReflection::type;
534  auto p = create_predicate_function<Field>(static_cast<restriction_function>(f), std::move(a));
535  return [p=std::move(p)](const Object& o) { return p(FieldReflection::get(o)); };
536  };
537  return typelist::runtime::dispatch(member_list(), static_cast<size_t>(r.member_index.value), predicator);
538 }
539 template<typename Object>
541  FC_THROW_EXCEPTION(fc::assert_exception, "Invalid restriction references member of non-object type: ${O}",
543 }
544 
545 template<typename Object>
547  FC_ASSERT(rs.size() > 1, "Logical OR must have at least two branches");
548  auto to_predicate = std::bind(restrictions_to_predicate<Object>, std::placeholders::_1, false);
549 
550  vector<object_restriction_predicate<Object>> predicates;
551  std::transform(std::make_move_iterator(rs.begin()), std::make_move_iterator(rs.end()),
552  std::back_inserter(predicates), to_predicate);
553 
554  return [predicates=std::move(predicates)](const Object& obj) {
555  vector<predicate_result> rejections;
556  bool success = std::any_of(predicates.begin(), predicates.end(),
557  [o=std::cref(obj), &rejections](const auto& p) {
558  auto result = p(o);
559  if (!result) rejections.push_back(std::move(result));
560  return !!result;
561  });
562  if (success) return predicate_result::Success();
563  return predicate_result::Rejection(std::move(rejections));
564  };
565 }
566 
567 template<typename Object>
568 object_restriction_predicate<Object> restrictions_to_predicate(vector<restriction> rs, bool allow_empty) {
569  if (!allow_empty)
570  FC_ASSERT(!rs.empty(), "Empty attribute assertions and logical OR branches are not permitted");
571 
572  vector<object_restriction_predicate<Object>> predicates;
573  std::transform(std::make_move_iterator(rs.begin()), std::make_move_iterator(rs.end()),
574  std::back_inserter(predicates), [](restriction&& r) {
575  if (r.restriction_type.value == restriction::func_logical_or) {
576  FC_ASSERT(r.argument.which() == restriction_argument::tag<vector<vector<restriction>>>::value,
577  "Restriction argument for logical OR function type must be list of restriction lists.");
578  return create_logical_or_predicate<Object>(std::move(r.argument.get<vector<vector<restriction>>>()));
579  }
580  return create_field_predicate<Object>(std::move(r), short());
581  });
582 
583  return [predicates=std::move(predicates)](const Object& obj) {
584  for (size_t i = 0; i < predicates.size(); ++i) {
585  auto result = predicates[i](obj);
586  if (!result) {
587  result.rejection_path.push_back(i);
588  return result;
589  }
590  }
591  return predicate_result::Success();
592  };
593 }
594 
595 } } // namespace graphene::protocol
bool operator()(const Field &f, const Container &c) const
static object_restriction_predicate< Variant > create(restriction::variant_assert_argument_type &&)
object_restriction_predicate< F > embed_argument(P p, A a, short)
static static_variant import_from(const static_variant< Other... > &other)
object_restriction_predicate< Object > create_logical_or_predicate(vector< vector< restriction >> rs)
constexpr bool operator()(const Field &f, const Argument &a) const
uint32_t sec_since_epoch() const
Definition: time.hpp:90
static object_restriction_predicate< extension< Extension > > create(vector< restriction > &&rs)
Definition: api.cpp:56
static object_restriction_predicate< Variant > create(restriction::variant_assert_argument_type &&arg)
bool operator()(const fc::optional< OptionalType > &f, const Argument &a) const
bool valid() const
Definition: optional.hpp:186
static predicate_result Rejection(rejection_reason reason)
tag_type which() const
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
static object_restriction_predicate< Optional > create(restriction::variant_assert_argument_type &&arg)
const auto & to_num(const I &i)
constexpr bool operator()(const Field &f, const Argument &a) const
constexpr bool operator()(const Field &f, const Argument &a) const
This namespace contains the list type, and all of the operations and queries which can be performed u...
Definition: typelist.hpp:14
bool operator()(const fc::optional< OptionalType > &f, const Argument &a) const
#define FC_CAPTURE_AND_RETHROW(...)
Definition: exception.hpp:478
object_restriction_predicate< Field > make_predicate(ArgVariant arg)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
Definition: exception.hpp:345
object_restriction_predicate< Object > restrictions_to_predicate(vector< restriction >, bool)
static object_restriction_predicate< Field > create(vector< restriction > &&rs)
bool operator()(const Field &f, const Argument &a) const
fc::static_variant< GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC > argument_type
Definition: restriction.hpp:99
template object_restriction_predicate< share_type > create_predicate_function(restriction_function func, restriction_argument arg)
constexpr bool operator()(const Field &f, const Argument &a) const
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
Definition: exception.hpp:378
typelist::list< int64_t, string, time_point_sec, account_id_type, asset_id_type, force_settlement_id_type, committee_member_id_type, witness_id_type, limit_order_id_type, call_order_id_type, custom_id_type, proposal_id_type, withdraw_permission_id_type, vesting_balance_id_type, worker_id_type, balance_id_type > comparable_types_list
typelist::transform< typelist::concat< typelist::list< bool, public_key_type, fc::sha256 >, comparable_types_list >, make_flat_set > list_types_list
The actual list type.
Definition: typelist.hpp:17
Defines exception&#39;s used by fc.
static object_restriction_predicate< fc::optional< Field > > create(vector< restriction > &&rs)
bool operator()(const fc::optional< Field > &f, const void_t &) const
std::function< predicate_result(const Field &)> object_restriction_predicate
typename impl::transform< List, Transformer >::type transform
Transform elements of a typelist.
Definition: typelist.hpp:170
pair< int64_t, vector< restriction >> variant_assert_argument_type
Definition: restriction.hpp:53
Definition: api.hpp:15
typename impl::concat< Lists... >::type concat
Concatenate two or more typelists together.
Definition: typelist.hpp:150
object_restriction_predicate< Object > create_field_predicate(restriction &&r, short)
Create a predicate asserting on the field of the object a restriction is referencing.
typename typelist::concat< typelist::list< void_t, bool, public_key_type, fc::sha256 >, comparable_types_list, list_types_list > equality_types_list
bool operator()(const A &, const B &) const
constexpr int8_t operator()(const fc::optional< Field > &f, const Argument &a) const
Return dispatch(list< Types... >, std::size_t index, Callable c)
Index into the typelist for a type T, and invoke the callable with an argument wrapper<T>() ...
Definition: typelist.hpp:243
T value
Definition: safe.hpp:22