31 namespace graphene {
namespace protocol {
42 template<
typename> constexpr
static bool is_safe =
false;
43 template<
typename I> constexpr
static bool is_safe<fc::safe<I>> =
true;
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);
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>));
61 template<
typename,
typename =
void>
68 template<
typename Field>
72 template<typename I, typename=std::enable_if_t<std::is_integral<I>::value>>
73 const auto&
to_num(
const I& i) {
return i; }
78 namespace safenum = boost::safe_numerics::safe_compare;
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>;
144 template<
typename A,
typename B>
146 constexpr
static bool valid =
false;
152 template<
typename Field,
typename Argument>
153 struct predicate_eq<Field, Argument,
std::enable_if_t<std::is_same<Field, Argument>::value>> {
156 constexpr
bool operator()(
const Field& f,
const Argument& a)
const {
return f == a; }
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>> {
165 template<
typename Field,
typename Argument>
166 struct predicate_eq<Field, Argument,
std::enable_if_t<is_container<Field> && is_integral<Argument>>> {
169 bool operator()(
const Field& f,
const Argument& a)
const {
return safenum::equal(f.size(),
to_num(a)); }
171 template<
typename Field,
typename Argument>
178 return (*
this)(*f, a);
181 template<
typename Field>
195 template<
typename Field,
typename Argument>
199 constexpr int8_t
operator()(
const Field& f,
const Argument& a)
const {
200 return f<a? -1 : (f>a? 1 : 0);
203 template<
typename Field,
typename Argument>
205 !std::is_same<Field, Argument>::value>> {
208 constexpr int8_t
operator()(
const Field& f,
const Argument& a)
const {
211 return safenum::less_than(nf, na)? -1 : (safenum::greater_than(nf, na)? 1 : 0);
214 template<
typename Field,
typename Argument>
220 return (*
this)(*f, a);
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>>> {
247 bool operator()(
const Field& f,
const flat_set<Element>& c)
const {
return c.count(f) != 0; }
249 template<
typename Field,
typename Element>
250 struct predicate_in<
fc::
safe<Field>, flat_set<Element>, std::enable_if_t<comparable_types<Field, Element>>> {
255 template<
typename Field,
typename Element>
261 return c.count(*f) != 0;
264 template<
typename Container,
typename Element>
266 std::enable_if_t<is_container<Container> &&
267 comparable_types<typename Container::value_type, Element>>> {
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; });
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());
287 template<
typename Container,
typename Element>
289 std::enable_if_t<is_container<Container> &&
290 comparable_types<typename Container::value_type, Element>>> {
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; });
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();
309 template<
typename FieldElement,
typename ArgumentElement>
311 std::enable_if_t<comparable_types<FieldElement, ArgumentElement>>> {
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());
319 template<
typename FieldContainer,
typename ArgumentElement>
321 std::enable_if_t<is_container<FieldContainer> && !is_flat_set<FieldContainer> &&
322 comparable_types<typename FieldContainer::value_type, ArgumentElement>>> {
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());
331 template<
typename OptionalType,
typename Argument>
336 return (*
this)(*f, a);
342 template<
typename FieldElement,
typename ArgumentElement>
344 std::enable_if_t<comparable_types<FieldElement, ArgumentElement>>> {
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();
354 template<
typename FieldContainer,
typename ArgumentElement>
356 std::enable_if_t<is_container<FieldContainer> && !is_flat_set<FieldContainer> &&
357 comparable_types<typename FieldContainer::value_type, ArgumentElement>>> {
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; });
364 template<
typename OptionalType,
typename Argument>
369 return (*
this)(*f, a);
377 template<
typename Field>
380 return restrictions_to_predicate<Field>(std::move(rs),
false);
383 template<
typename Field>
386 return [p=restrictions_to_predicate<Field>(std::move(rs),
false)](
const fc::optional<Field>& f) {
392 template<
typename Extension>
395 return [p=restrictions_to_predicate<Extension>(std::move(rs),
false)](
const extension<Extension>& x) {
401 template<
typename Variant>
404 FC_THROW_EXCEPTION(fc::assert_exception,
"Invalid variant assertion on non-variant field",
408 template<
typename... Types>
412 template<
typename Value>
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>());
423 using Value = typename decltype(t)::type;
424 return variant_assertion::make_predicate<Value>(std::move(arg.second));
428 template<
typename... Types>
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);
446 template<
typename F,
typename P,
typename A,
typename = std::enable_if_t<P::val
id>>
448 return [p=std::move(p), a=std::move(a)](
const F& f) {
449 if (p(f, a))
return predicate_result::Success();
450 return predicate_result::Rejection(predicate_result::predicate_was_false);
453 template<
typename F,
typename P,
typename A>
459 template<
template<
typename...>
class Predicate,
typename Field,
typename ArgVariant>
463 using Arg = typename decltype(t)::type;
464 return embed_argument<Field>(Predicate<Field, Arg>(), std::move(arg.template get<Arg>()), short());
468 template<
typename Field>
472 case restriction::func_eq:
474 case restriction::func_ne:
476 case restriction::func_lt:
478 ::import_from(std::move(arg)));
479 case restriction::func_le:
481 ::import_from(std::move(arg)));
482 case restriction::func_gt:
484 ::import_from(std::move(arg)));
485 case restriction::func_ge:
487 ::import_from(std::move(arg)));
488 case restriction::func_in:
490 case restriction::func_not_in:
492 ::import_from(std::move(arg)));
493 case restriction::func_has_all:
495 ::import_from(std::move(arg)));
496 case restriction::func_has_none:
498 ::import_from(std::move(arg)));
499 case restriction::func_attr:
500 FC_ASSERT(arg.
which() == restriction_argument::tag<vector<restriction>>::value,
501 "Argument type for attribute assertion must be restriction list");
503 case restriction::func_variant_assert:
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");
524 template<
typename Object,
525 typename = std::enable_if_t<typelist::length<typename fc::reflector<Object>::native_members>() != 0>>
528 FC_ASSERT( r.member_index <
static_cast<uint64_t
>(typelist::length<member_list>()),
529 "Invalid member index ${I} for object ${O}",
532 using FieldReflection =
typename decltype(t)::type;
533 using Field =
typename FieldReflection::type;
535 return [p=std::move(p)](
const Object& o) {
return p(FieldReflection::get(o)); };
539 template<
typename Object>
541 FC_THROW_EXCEPTION(fc::assert_exception,
"Invalid restriction references member of non-object type: ${O}",
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);
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);
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) {
559 if (!result) rejections.push_back(std::move(result));
562 if (success)
return predicate_result::Success();
563 return predicate_result::Rejection(std::move(rejections));
567 template<
typename Object>
570 FC_ASSERT(!rs.empty(),
"Empty attribute assertions and logical OR branches are not permitted");
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>>>()));
580 return create_field_predicate<Object>(std::move(r),
short());
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);
587 result.rejection_path.push_back(i);
591 return predicate_result::Success();