Skip to content

Commit 3cd47d1

Browse files
[BSIP40] Add field support check
See https://github.com/bitshares/bitshares-core/pull/ 2093#discussion_r401052309 A compile error is now thrown if any operation field type is unsupported in use in any predicate with any argument type. See https://github.com/bitshares/bitshares-core/pull/ 2093#discussion_r400286103 Unsigned_int is now supported as an integral type
1 parent bc5c34b commit 3cd47d1

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

libraries/protocol/custom_authorities/restriction_predicate.hxx

+64-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
*/
2424

2525
#include <graphene/protocol/restriction_predicate.hpp>
26+
#include <graphene/protocol/fee_schedule.hpp>
2627

2728
#include <fc/exception/exception.hpp>
2829

@@ -50,7 +51,8 @@ template<typename T> constexpr static bool is_flat_set = is_flat_set_impl<T>::va
5051
// We use our own is_integral which does not consider bools integral (to disallow comparison between bool and ints)
5152
template<typename T> constexpr static bool is_integral = !std::is_same<T, bool>::value &&
5253
!std::is_same<T, safe<bool>>::value &&
53-
(is_safe<T> || std::is_integral<T>::value);
54+
(is_safe<T> || std::is_integral<T>::value ||
55+
std::is_same<T, fc::unsigned_int>::value);
5456

5557
// Metafunction to check if two types are comparable, which means not void_t, and either the same or both integral
5658
template<typename T, typename U>
@@ -74,6 +76,7 @@ const auto& to_num(const I& i) { return i; }
7476
template<typename I>
7577
const auto& to_num(const fc::safe<I>& i) { return i.value; }
7678
inline auto to_num(const fc::time_point_sec& t) { return t.sec_since_epoch(); }
79+
inline auto to_num(const fc::unsigned_int& ui) { return ui.value; }
7780

7881
namespace safenum = boost::safe_numerics::safe_compare;
7982

@@ -397,6 +400,14 @@ struct attribute_assertion<extension<Extension>> {
397400
};
398401
}
399402
};
403+
template<typename Pointed>
404+
struct attribute_assertion<std::shared_ptr<Pointed>> {
405+
static object_restriction_predicate<std::shared_ptr<Pointed>> create(vector<restriction>&& rs) {
406+
return [p=restrictions_to_predicate<Pointed>(std::move(rs), false)](const shared_ptr<Pointed>& x) {
407+
return p(*x);
408+
};
409+
}
410+
};
400411

401412
template<typename Variant>
402413
struct variant_assertion {
@@ -465,8 +476,59 @@ object_restriction_predicate<Field> make_predicate(ArgVariant arg) {
465476
});
466477
}
467478

479+
// A template checking whether a predicate is valid with the provided field type and any restriction argument type
480+
template<typename Field, typename = void>
481+
struct predicate_is_valid_for_field {
482+
template<typename Predicate>
483+
struct filter {
484+
template<typename Argument>
485+
struct argument_filter {
486+
constexpr static bool value = Predicate::template unwrap<Field, Argument>::valid;
487+
};
488+
489+
constexpr static bool value = typelist::any<restriction::argument_type::list, argument_filter>;
490+
};
491+
};
492+
// Specialization for reflected struct fields; they are always valid because we can use an attribute_assert on them
493+
template<typename Struct>
494+
struct predicate_is_valid_for_field<Struct, std::enable_if_t<fc::reflector<Struct>::is_defined::value>> {
495+
template<typename>
496+
struct filter { constexpr static bool value = true; };
497+
};
498+
// Specialization for extension fields; they are always valid because we can use an attribute_assert on them
499+
template<typename Ext>
500+
struct predicate_is_valid_for_field<extension<Ext>, void> {
501+
template<typename>
502+
struct filter { constexpr static bool value = true; };
503+
};
504+
// Specialization for static variant fields; they are always valid because we can use a variant_assert on them
505+
template<typename... Ts>
506+
struct predicate_is_valid_for_field<static_variant<Ts...>, void> {
507+
template<typename>
508+
struct filter { constexpr static bool value = true; };
509+
};
510+
// Specialization for shared_ptr fields; they are valid if the thing pointed to is
511+
template<typename Pointed>
512+
struct predicate_is_valid_for_field<std::shared_ptr<Pointed>, void>
513+
: public predicate_is_valid_for_field<std::decay_t<Pointed>> {};
514+
515+
// Check if any predicate can be used with the provided field type and any known argument type
516+
template<typename Field>
517+
constexpr bool any_predicate_applies() {
518+
using PredicateTypes = typelist::list<typelist::wrapped<predicate_eq>, typelist::wrapped<predicate_ne>,
519+
typelist::wrapped<predicate_lt>, typelist::wrapped<predicate_le>,
520+
typelist::wrapped<predicate_gt>, typelist::wrapped<predicate_ge>,
521+
typelist::wrapped<predicate_in>, typelist::wrapped<predicate_not_in>,
522+
typelist::wrapped<predicate_has_all>, typelist::wrapped<predicate_has_none>>;
523+
return typelist::any<PredicateTypes, predicate_is_valid_for_field<Field>::template filter>;
524+
}
525+
468526
template<typename Field>
469527
object_restriction_predicate<Field> create_predicate_function(restriction_function func, restriction_argument arg) {
528+
// This checks that all fields of all objects can be used with at least one predicate
529+
static_assert(any_predicate_applies<Field>(),
530+
"This new field type is not yet supported by Custom Active Authorities. Please add support for it.");
531+
470532
try {
471533
switch(func) {
472534
case restriction::func_eq:
@@ -539,7 +601,7 @@ object_restriction_predicate<Object> create_field_predicate(restriction&& r, sho
539601
template<typename Object>
540602
object_restriction_predicate<Object> create_field_predicate(restriction&&, long) {
541603
FC_THROW_EXCEPTION(fc::assert_exception, "Invalid restriction references member of non-object type: ${O}",
542-
("O", fc::get_typename<Object>::name()));
604+
("O", fc::get_typename<std::decay_t<Object>>::name()));
543605
}
544606

545607
template<typename Object>

0 commit comments

Comments
 (0)