From ab113b2fc48fa935b80da475db3843c8276b857f Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Tue, 1 Sep 2020 17:46:52 -0500 Subject: [PATCH] Add support for multiple evaluators per operation type This commit adds the ability to register multiple evaluator types for a given operation type. This will be used to allow plug-ins to define their own evaluators for various operation types (most notably, custom operations) so that they may be used to carry app-specific data which can be parsed by a plug-in. --- .../chain/include/graphene/chain/database.hpp | 20 +++++++++++++++++-- .../include/graphene/chain/evaluator.hpp | 13 +++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index f3c56ead..7e829f00 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -344,11 +344,27 @@ namespace graphene { namespace chain { void initialize_indexes(); void init_genesis(const genesis_state_type& genesis_state = genesis_state_type()); + /** + * @brief Register a new evaluator to the evaluator chain for its operation type + * @tparam EvaluatorType An evaluator type which will be used to evaluate its declared operation type + * + * This method registers a new evaluator type with tthe database. The evaluator specifies an operation type + * which it should be used to evaluate. The evaluator will be instantiated each time an operaton of the + * appropriate type is processed and used to evaluate the operation. + * + * This method may be called more than once with multiple evaluator types for a given operation type. When + * multiple evaluator types are registered for a given operation type, they will all execute in the order of + * registration; however, only the return value of the first registered evaluator will be returned; return + * values of subsequently registered evaluators will be silently dropped. + */ template void register_evaluator() { - _operation_evaluators[ - operation::tag::value].reset( new op_evaluator_impl() ); + auto& eval_ptr = _operation_evaluators[operation::tag::value]; + if (eval_ptr == nullptr) + eval_ptr = std::make_unique>(); + else + eval_ptr->append_evaluator(std::make_unique>()); } //////////////////// db_balance.cpp //////////////////// diff --git a/libraries/chain/include/graphene/chain/evaluator.hpp b/libraries/chain/include/graphene/chain/evaluator.hpp index 0a1cc986..25680528 100644 --- a/libraries/chain/include/graphene/chain/evaluator.hpp +++ b/libraries/chain/include/graphene/chain/evaluator.hpp @@ -124,17 +124,28 @@ namespace graphene { namespace chain { { public: virtual ~op_evaluator(){} + virtual void append_evaluator(unique_ptr next_evaluator) = 0; virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) = 0; }; template class op_evaluator_impl : public op_evaluator { + unique_ptr next_evaluator; public: + virtual void append_evaluator(unique_ptr next_evaluator) override { + if (this->next_evaluator == nullptr) + this->next_evaluator = std::move(next_evaluator); + else + this->next_evaluator->append_evaluator(std::move(next_evaluator)); + } virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply = true) override { T eval; - return eval.start_evaluate(eval_state, op, apply); + auto result = eval.start_evaluate(eval_state, op, apply); + if (next_evaluator != nullptr) + next_evaluator->evaluate(eval_state, op, apply); + return result; } };