Safety Check: Part 1 -- Evaluator Tagging

Pursuant to the requested safety checks on the database, to ensure that
plugin code (i.e., third party code) cannot modify the database, we
implement evaluator tagging so the chain can distinguish between
consensus evaluators and third party evaluators. Also, define a new kind
of evaluator base class, third_party_evaluator, so that fees are not
charged multiple times for operations with multiple evaluators.

Next step, implement the actual safety check mechanism on the database.
This commit is contained in:
Nathaniel 2022-03-07 16:37:53 -06:00
parent 659d135b9b
commit e8b432c19f
No known key found for this signature in database
GPG key ID: B4344309A110851E
42 changed files with 501 additions and 284 deletions

View file

@ -130,7 +130,7 @@ void asset_create_evaluator::pay_fee()
{
fee_is_odd = core_fee_paid.value & 1;
core_fee_paid -= core_fee_paid.value/2;
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
}
object_id_type asset_create_evaluator::do_apply( const asset_create_operation& op )
@ -283,7 +283,7 @@ void lottery_asset_create_evaluator::pay_fee()
{
fee_is_odd = core_fee_paid.value & 1;
core_fee_paid -= core_fee_paid.value/2;
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
}
object_id_type lottery_asset_create_evaluator::do_apply( const lottery_asset_create_operation& op )

View file

@ -74,7 +74,7 @@ void transfer_to_blind_evaluator::pay_fee()
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_transfer_to_blind );
else
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
}
void_result transfer_from_blind_evaluator::do_evaluate( const transfer_from_blind_operation& o )
@ -118,7 +118,7 @@ void transfer_from_blind_evaluator::pay_fee()
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_transfer_from_blind );
else
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
}
void_result blind_transfer_evaluator::do_evaluate( const blind_transfer_operation& o )
@ -175,7 +175,7 @@ void blind_transfer_evaluator::pay_fee()
if( db().head_block_time() >= HARDFORK_563_TIME )
pay_fba_fee( fba_accumulator_id_blind_transfer );
else
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
}
} } // graphene::chain

View file

@ -42,6 +42,7 @@
#include <graphene/protocol/betting_market.hpp>
#include <fc/crypto/digest.hpp>
#include <fc/thread/non_preemptable_scope_check.hpp>
namespace {
@ -866,12 +867,18 @@ operation_result database::apply_operation(transaction_evaluation_state& eval_st
int i_which = op.which();
uint64_t u_which = uint64_t( i_which );
FC_ASSERT( i_which >= 0, "Negative operation tag in operation ${op}", ("op",op) );
FC_ASSERT( u_which < _operation_evaluators.size(), "No registered evaluator for operation ${op}", ("op",op) );
unique_ptr<op_evaluator>& eval = _operation_evaluators[ u_which ];
FC_ASSERT( u_which < _consensus_operation_evaluators.size(), "No registered evaluator for operation ${op}", ("op",op) );
unique_ptr<op_evaluator>& eval = _consensus_operation_evaluators[ u_which ];
FC_ASSERT( eval, "No registered evaluator for operation ${op}", ("op",op) );
auto op_id = push_applied_operation( op );
auto result = eval->evaluate( eval_state, op, true );
set_applied_operation_result( op_id, result );
// Run third party evaluator chain
if (_third_party_operation_evaluators.size() > u_which && _third_party_operation_evaluators[u_which]) {
ASSERT_TASK_NOT_PREEMPTED();
_third_party_operation_evaluators[u_which]->evaluate( eval_state, op, true );
}
return result;
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -214,119 +214,120 @@ const uint8_t random_number_object::type_id;
void database::initialize_evaluators()
{
_operation_evaluators.resize(255);
register_evaluator<account_create_evaluator>();
register_evaluator<account_update_evaluator>();
register_evaluator<account_upgrade_evaluator>();
register_evaluator<account_whitelist_evaluator>();
register_evaluator<committee_member_create_evaluator>();
register_evaluator<committee_member_update_evaluator>();
register_evaluator<committee_member_update_global_parameters_evaluator>();
register_evaluator<custom_evaluator>();
register_evaluator<asset_create_evaluator>();
register_evaluator<asset_issue_evaluator>();
register_evaluator<asset_reserve_evaluator>();
register_evaluator<asset_update_evaluator>();
register_evaluator<asset_update_bitasset_evaluator>();
register_evaluator<asset_update_dividend_evaluator>();
register_evaluator<asset_update_feed_producers_evaluator>();
register_evaluator<asset_settle_evaluator>();
register_evaluator<asset_global_settle_evaluator>();
register_evaluator<assert_evaluator>();
register_evaluator<limit_order_create_evaluator>();
register_evaluator<limit_order_cancel_evaluator>();
register_evaluator<call_order_update_evaluator>();
register_evaluator<transfer_evaluator>();
register_evaluator<override_transfer_evaluator>();
register_evaluator<asset_fund_fee_pool_evaluator>();
register_evaluator<asset_publish_feeds_evaluator>();
register_evaluator<proposal_create_evaluator>();
register_evaluator<proposal_update_evaluator>();
register_evaluator<proposal_delete_evaluator>();
register_evaluator<vesting_balance_create_evaluator>();
register_evaluator<vesting_balance_withdraw_evaluator>();
register_evaluator<witness_create_evaluator>();
register_evaluator<witness_update_evaluator>();
register_evaluator<withdraw_permission_create_evaluator>();
register_evaluator<withdraw_permission_claim_evaluator>();
register_evaluator<withdraw_permission_update_evaluator>();
register_evaluator<withdraw_permission_delete_evaluator>();
register_evaluator<worker_create_evaluator>();
register_evaluator<balance_claim_evaluator>();
register_evaluator<transfer_to_blind_evaluator>();
register_evaluator<transfer_from_blind_evaluator>();
register_evaluator<blind_transfer_evaluator>();
register_evaluator<asset_claim_fees_evaluator>();
register_evaluator<sport_create_evaluator>();
register_evaluator<sport_update_evaluator>();
register_evaluator<sport_delete_evaluator>();
register_evaluator<event_group_create_evaluator>();
register_evaluator<event_group_update_evaluator>();
register_evaluator<event_group_delete_evaluator>();
register_evaluator<event_create_evaluator>();
register_evaluator<event_update_evaluator>();
register_evaluator<event_update_status_evaluator>();
register_evaluator<betting_market_rules_create_evaluator>();
register_evaluator<betting_market_rules_update_evaluator>();
register_evaluator<betting_market_group_create_evaluator>();
register_evaluator<betting_market_group_update_evaluator>();
register_evaluator<betting_market_create_evaluator>();
register_evaluator<betting_market_update_evaluator>();
register_evaluator<bet_place_evaluator>();
register_evaluator<bet_cancel_evaluator>();
register_evaluator<betting_market_group_resolve_evaluator>();
register_evaluator<betting_market_group_cancel_unmatched_bets_evaluator>();
register_evaluator<tournament_create_evaluator>();
register_evaluator<tournament_join_evaluator>();
register_evaluator<game_move_evaluator>();
register_evaluator<tournament_leave_evaluator>();
register_evaluator<lottery_asset_create_evaluator>();
register_evaluator<ticket_purchase_evaluator>();
register_evaluator<lottery_reward_evaluator>();
register_evaluator<lottery_end_evaluator>();
register_evaluator<sweeps_vesting_claim_evaluator>();
register_evaluator<create_custom_permission_evaluator>();
register_evaluator<update_custom_permission_evaluator>();
register_evaluator<delete_custom_permission_evaluator>();
register_evaluator<create_custom_account_authority_evaluator>();
register_evaluator<update_custom_account_authority_evaluator>();
register_evaluator<delete_custom_account_authority_evaluator>();
register_evaluator<offer_evaluator>();
register_evaluator<bid_evaluator>();
register_evaluator<cancel_offer_evaluator>();
register_evaluator<finalize_offer_evaluator>();
register_evaluator<nft_metadata_create_evaluator>();
register_evaluator<nft_metadata_update_evaluator>();
register_evaluator<nft_mint_evaluator>();
register_evaluator<nft_safe_transfer_from_evaluator>();
register_evaluator<nft_approve_evaluator>();
register_evaluator<nft_set_approval_for_all_evaluator>();
register_evaluator<account_role_create_evaluator>();
register_evaluator<account_role_update_evaluator>();
register_evaluator<account_role_delete_evaluator>();
register_evaluator<nft_lottery_token_purchase_evaluator>();
register_evaluator<nft_lottery_reward_evaluator>();
register_evaluator<nft_lottery_end_evaluator>();
register_evaluator<create_son_evaluator>();
register_evaluator<update_son_evaluator>();
register_evaluator<deregister_son_evaluator>();
register_evaluator<son_heartbeat_evaluator>();
register_evaluator<son_report_down_evaluator>();
register_evaluator<son_maintenance_evaluator>();
register_evaluator<recreate_son_wallet_evaluator>();
register_evaluator<update_son_wallet_evaluator>();
register_evaluator<create_son_wallet_deposit_evaluator>();
register_evaluator<process_son_wallet_deposit_evaluator>();
register_evaluator<create_son_wallet_withdraw_evaluator>();
register_evaluator<process_son_wallet_withdraw_evaluator>();
register_evaluator<add_sidechain_address_evaluator>();
register_evaluator<update_sidechain_address_evaluator>();
register_evaluator<delete_sidechain_address_evaluator>();
register_evaluator<sidechain_transaction_create_evaluator>();
register_evaluator<sidechain_transaction_sign_evaluator>();
register_evaluator<sidechain_transaction_send_evaluator>();
register_evaluator<sidechain_transaction_settle_evaluator>();
register_evaluator<random_number_store_evaluator>();
_consensus_operation_evaluators.resize(255);
_third_party_operation_evaluators.resize(255);
register_consensus_evaluator<account_create_evaluator>();
register_consensus_evaluator<account_update_evaluator>();
register_consensus_evaluator<account_upgrade_evaluator>();
register_consensus_evaluator<account_whitelist_evaluator>();
register_consensus_evaluator<committee_member_create_evaluator>();
register_consensus_evaluator<committee_member_update_evaluator>();
register_consensus_evaluator<committee_member_update_global_parameters_evaluator>();
register_consensus_evaluator<custom_evaluator>();
register_consensus_evaluator<asset_create_evaluator>();
register_consensus_evaluator<asset_issue_evaluator>();
register_consensus_evaluator<asset_reserve_evaluator>();
register_consensus_evaluator<asset_update_evaluator>();
register_consensus_evaluator<asset_update_bitasset_evaluator>();
register_consensus_evaluator<asset_update_dividend_evaluator>();
register_consensus_evaluator<asset_update_feed_producers_evaluator>();
register_consensus_evaluator<asset_settle_evaluator>();
register_consensus_evaluator<asset_global_settle_evaluator>();
register_consensus_evaluator<assert_evaluator>();
register_consensus_evaluator<limit_order_create_evaluator>();
register_consensus_evaluator<limit_order_cancel_evaluator>();
register_consensus_evaluator<call_order_update_evaluator>();
register_consensus_evaluator<transfer_evaluator>();
register_consensus_evaluator<override_transfer_evaluator>();
register_consensus_evaluator<asset_fund_fee_pool_evaluator>();
register_consensus_evaluator<asset_publish_feeds_evaluator>();
register_consensus_evaluator<proposal_create_evaluator>();
register_consensus_evaluator<proposal_update_evaluator>();
register_consensus_evaluator<proposal_delete_evaluator>();
register_consensus_evaluator<vesting_balance_create_evaluator>();
register_consensus_evaluator<vesting_balance_withdraw_evaluator>();
register_consensus_evaluator<witness_create_evaluator>();
register_consensus_evaluator<witness_update_evaluator>();
register_consensus_evaluator<withdraw_permission_create_evaluator>();
register_consensus_evaluator<withdraw_permission_claim_evaluator>();
register_consensus_evaluator<withdraw_permission_update_evaluator>();
register_consensus_evaluator<withdraw_permission_delete_evaluator>();
register_consensus_evaluator<worker_create_evaluator>();
register_consensus_evaluator<balance_claim_evaluator>();
register_consensus_evaluator<transfer_to_blind_evaluator>();
register_consensus_evaluator<transfer_from_blind_evaluator>();
register_consensus_evaluator<blind_transfer_evaluator>();
register_consensus_evaluator<asset_claim_fees_evaluator>();
register_consensus_evaluator<sport_create_evaluator>();
register_consensus_evaluator<sport_update_evaluator>();
register_consensus_evaluator<sport_delete_evaluator>();
register_consensus_evaluator<event_group_create_evaluator>();
register_consensus_evaluator<event_group_update_evaluator>();
register_consensus_evaluator<event_group_delete_evaluator>();
register_consensus_evaluator<event_create_evaluator>();
register_consensus_evaluator<event_update_evaluator>();
register_consensus_evaluator<event_update_status_evaluator>();
register_consensus_evaluator<betting_market_rules_create_evaluator>();
register_consensus_evaluator<betting_market_rules_update_evaluator>();
register_consensus_evaluator<betting_market_group_create_evaluator>();
register_consensus_evaluator<betting_market_group_update_evaluator>();
register_consensus_evaluator<betting_market_create_evaluator>();
register_consensus_evaluator<betting_market_update_evaluator>();
register_consensus_evaluator<bet_place_evaluator>();
register_consensus_evaluator<bet_cancel_evaluator>();
register_consensus_evaluator<betting_market_group_resolve_evaluator>();
register_consensus_evaluator<betting_market_group_cancel_unmatched_bets_evaluator>();
register_consensus_evaluator<tournament_create_evaluator>();
register_consensus_evaluator<tournament_join_evaluator>();
register_consensus_evaluator<game_move_evaluator>();
register_consensus_evaluator<tournament_leave_evaluator>();
register_consensus_evaluator<lottery_asset_create_evaluator>();
register_consensus_evaluator<ticket_purchase_evaluator>();
register_consensus_evaluator<lottery_reward_evaluator>();
register_consensus_evaluator<lottery_end_evaluator>();
register_consensus_evaluator<sweeps_vesting_claim_evaluator>();
register_consensus_evaluator<create_custom_permission_evaluator>();
register_consensus_evaluator<update_custom_permission_evaluator>();
register_consensus_evaluator<delete_custom_permission_evaluator>();
register_consensus_evaluator<create_custom_account_authority_evaluator>();
register_consensus_evaluator<update_custom_account_authority_evaluator>();
register_consensus_evaluator<delete_custom_account_authority_evaluator>();
register_consensus_evaluator<offer_evaluator>();
register_consensus_evaluator<bid_evaluator>();
register_consensus_evaluator<cancel_offer_evaluator>();
register_consensus_evaluator<finalize_offer_evaluator>();
register_consensus_evaluator<nft_metadata_create_evaluator>();
register_consensus_evaluator<nft_metadata_update_evaluator>();
register_consensus_evaluator<nft_mint_evaluator>();
register_consensus_evaluator<nft_safe_transfer_from_evaluator>();
register_consensus_evaluator<nft_approve_evaluator>();
register_consensus_evaluator<nft_set_approval_for_all_evaluator>();
register_consensus_evaluator<account_role_create_evaluator>();
register_consensus_evaluator<account_role_update_evaluator>();
register_consensus_evaluator<account_role_delete_evaluator>();
register_consensus_evaluator<nft_lottery_token_purchase_evaluator>();
register_consensus_evaluator<nft_lottery_reward_evaluator>();
register_consensus_evaluator<nft_lottery_end_evaluator>();
register_consensus_evaluator<create_son_evaluator>();
register_consensus_evaluator<update_son_evaluator>();
register_consensus_evaluator<deregister_son_evaluator>();
register_consensus_evaluator<son_heartbeat_evaluator>();
register_consensus_evaluator<son_report_down_evaluator>();
register_consensus_evaluator<son_maintenance_evaluator>();
register_consensus_evaluator<recreate_son_wallet_evaluator>();
register_consensus_evaluator<update_son_wallet_evaluator>();
register_consensus_evaluator<create_son_wallet_deposit_evaluator>();
register_consensus_evaluator<process_son_wallet_deposit_evaluator>();
register_consensus_evaluator<create_son_wallet_withdraw_evaluator>();
register_consensus_evaluator<process_son_wallet_withdraw_evaluator>();
register_consensus_evaluator<add_sidechain_address_evaluator>();
register_consensus_evaluator<update_sidechain_address_evaluator>();
register_consensus_evaluator<delete_sidechain_address_evaluator>();
register_consensus_evaluator<sidechain_transaction_create_evaluator>();
register_consensus_evaluator<sidechain_transaction_sign_evaluator>();
register_consensus_evaluator<sidechain_transaction_send_evaluator>();
register_consensus_evaluator<sidechain_transaction_settle_evaluator>();
register_consensus_evaluator<random_number_store_evaluator>();
}
void database::initialize_indexes()

View file

@ -36,9 +36,9 @@
#include <graphene/protocol/fee_schedule.hpp>
namespace graphene { namespace chain {
database& generic_evaluator::db()const { return trx_state->db(); }
database& consensus_evaluator::db()const { return trx_state->db(); }
operation_result generic_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
operation_result consensus_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply )
{ try {
trx_state = &eval_state;
//check_required_authorities(op);
@ -48,7 +48,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
return result;
} FC_CAPTURE_AND_RETHROW() }
void generic_evaluator::prepare_fee(account_id_type account_id, asset fee)
void consensus_evaluator::prepare_fee(account_id_type account_id, asset fee)
{
const database& d = db();
fee_from_account = fee;
@ -77,7 +77,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
}
}
void generic_evaluator::convert_fee()
void consensus_evaluator::convert_fee()
{
if( !trx_state->skip_fee ) {
if( fee_asset->get_id() != asset_id_type() )
@ -90,7 +90,7 @@ database& generic_evaluator::db()const { return trx_state->db(); }
}
}
void generic_evaluator::pay_fee()
void consensus_evaluator::pay_fee()
{ try {
if( !trx_state->skip_fee ) {
database& d = db();
@ -102,13 +102,13 @@ database& generic_evaluator::db()const { return trx_state->db(); }
}
} FC_CAPTURE_AND_RETHROW() }
void generic_evaluator::pay_fba_fee( uint64_t fba_id )
void consensus_evaluator::pay_fba_fee( uint64_t fba_id )
{
database& d = db();
const fba_accumulator_object& fba = d.get< fba_accumulator_object >( fba_accumulator_id_type( fba_id ) );
if( !fba.is_configured(d) )
{
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
return;
}
d.modify( fba, [&]( fba_accumulator_object& _fba )
@ -117,16 +117,16 @@ database& generic_evaluator::db()const { return trx_state->db(); }
} );
}
share_type generic_evaluator::calculate_fee_for_operation(const operation& op) const
share_type consensus_evaluator::calculate_fee_for_operation(const operation& op) const
{
return db().current_fee_schedule().calculate_fee( op ).amount;
}
void generic_evaluator::db_adjust_balance(const account_id_type& fee_payer, asset fee_from_account)
void consensus_evaluator::db_adjust_balance(const account_id_type& fee_payer, asset fee_from_account)
{
db().adjust_balance(fee_payer, fee_from_account);
}
object_id_type generic_evaluator::get_relative_id( object_id_type rel_id )const
object_id_type consensus_evaluator::get_relative_id( object_id_type rel_id )const
{
if (!is_relative(rel_id))
FC_THROW("get_relative_id() called for non-relative id ${id}", ("id", rel_id));

View file

@ -27,7 +27,7 @@
namespace graphene { namespace chain {
class account_create_evaluator : public evaluator<account_create_evaluator>
class account_create_evaluator : public fee_handling_evaluator<account_create_evaluator>
{
public:
typedef account_create_operation operation_type;
@ -36,7 +36,7 @@ public:
object_id_type do_apply( const account_create_operation& o ) ;
};
class account_update_evaluator : public evaluator<account_update_evaluator>
class account_update_evaluator : public fee_handling_evaluator<account_update_evaluator>
{
public:
typedef account_update_operation operation_type;
@ -47,7 +47,7 @@ public:
const account_object* acnt;
};
class account_upgrade_evaluator : public evaluator<account_upgrade_evaluator>
class account_upgrade_evaluator : public fee_handling_evaluator<account_upgrade_evaluator>
{
public:
typedef account_upgrade_operation operation_type;
@ -58,7 +58,7 @@ public:
const account_object* account;
};
class account_whitelist_evaluator : public evaluator<account_whitelist_evaluator>
class account_whitelist_evaluator : public fee_handling_evaluator<account_whitelist_evaluator>
{
public:
typedef account_whitelist_operation operation_type;

View file

@ -7,7 +7,7 @@
namespace graphene { namespace chain {
class account_role_create_evaluator : public evaluator<account_role_create_evaluator>
class account_role_create_evaluator : public fee_handling_evaluator<account_role_create_evaluator>
{
public:
typedef account_role_create_operation operation_type;
@ -15,7 +15,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const account_role_create_operation& o );
};
class account_role_update_evaluator : public evaluator<account_role_update_evaluator>
class account_role_update_evaluator : public fee_handling_evaluator<account_role_update_evaluator>
{
public:
typedef account_role_update_operation operation_type;
@ -23,7 +23,7 @@ namespace graphene { namespace chain {
void_result do_apply( const account_role_update_operation& o );
};
class account_role_delete_evaluator : public evaluator<account_role_delete_evaluator>
class account_role_delete_evaluator : public fee_handling_evaluator<account_role_delete_evaluator>
{
public:
typedef account_role_delete_operation operation_type;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class assert_evaluator : public evaluator<assert_evaluator>
class assert_evaluator : public fee_handling_evaluator<assert_evaluator>
{
public:
typedef assert_operation operation_type;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class asset_create_evaluator : public evaluator<asset_create_evaluator>
class asset_create_evaluator : public fee_handling_evaluator<asset_create_evaluator>
{
public:
typedef asset_create_operation operation_type;
@ -44,7 +44,7 @@ namespace graphene { namespace chain {
bool fee_is_odd;
};
class lottery_asset_create_evaluator : public evaluator<lottery_asset_create_evaluator>
class lottery_asset_create_evaluator : public fee_handling_evaluator<lottery_asset_create_evaluator>
{
public:
typedef lottery_asset_create_operation operation_type;
@ -60,7 +60,7 @@ namespace graphene { namespace chain {
bool fee_is_odd;
};
class asset_issue_evaluator : public evaluator<asset_issue_evaluator>
class asset_issue_evaluator : public fee_handling_evaluator<asset_issue_evaluator>
{
public:
typedef asset_issue_operation operation_type;
@ -71,7 +71,7 @@ namespace graphene { namespace chain {
const account_object* to_account = nullptr;
};
class asset_reserve_evaluator : public evaluator<asset_reserve_evaluator>
class asset_reserve_evaluator : public fee_handling_evaluator<asset_reserve_evaluator>
{
public:
typedef asset_reserve_operation operation_type;
@ -83,7 +83,7 @@ namespace graphene { namespace chain {
};
class asset_update_evaluator : public evaluator<asset_update_evaluator>
class asset_update_evaluator : public fee_handling_evaluator<asset_update_evaluator>
{
public:
typedef asset_update_operation operation_type;
@ -94,7 +94,7 @@ namespace graphene { namespace chain {
const asset_object* asset_to_update = nullptr;
};
class asset_update_bitasset_evaluator : public evaluator<asset_update_bitasset_evaluator>
class asset_update_bitasset_evaluator : public fee_handling_evaluator<asset_update_bitasset_evaluator>
{
public:
typedef asset_update_bitasset_operation operation_type;
@ -105,7 +105,7 @@ namespace graphene { namespace chain {
const asset_bitasset_data_object* bitasset_to_update = nullptr;
};
class asset_update_dividend_evaluator : public evaluator<asset_update_dividend_evaluator>
class asset_update_dividend_evaluator : public fee_handling_evaluator<asset_update_dividend_evaluator>
{
public:
typedef asset_update_dividend_operation operation_type;
@ -117,7 +117,7 @@ namespace graphene { namespace chain {
const asset_dividend_data_object* asset_dividend_data_to_update = nullptr;
};
class asset_update_feed_producers_evaluator : public evaluator<asset_update_feed_producers_evaluator>
class asset_update_feed_producers_evaluator : public fee_handling_evaluator<asset_update_feed_producers_evaluator>
{
public:
typedef asset_update_feed_producers_operation operation_type;
@ -128,7 +128,7 @@ namespace graphene { namespace chain {
const asset_bitasset_data_object* bitasset_to_update = nullptr;
};
class asset_fund_fee_pool_evaluator : public evaluator<asset_fund_fee_pool_evaluator>
class asset_fund_fee_pool_evaluator : public fee_handling_evaluator<asset_fund_fee_pool_evaluator>
{
public:
typedef asset_fund_fee_pool_operation operation_type;
@ -139,7 +139,7 @@ namespace graphene { namespace chain {
const asset_dynamic_data_object* asset_dyn_data = nullptr;
};
class asset_global_settle_evaluator : public evaluator<asset_global_settle_evaluator>
class asset_global_settle_evaluator : public fee_handling_evaluator<asset_global_settle_evaluator>
{
public:
typedef asset_global_settle_operation operation_type;
@ -149,7 +149,7 @@ namespace graphene { namespace chain {
const asset_object* asset_to_settle = nullptr;
};
class asset_settle_evaluator : public evaluator<asset_settle_evaluator>
class asset_settle_evaluator : public fee_handling_evaluator<asset_settle_evaluator>
{
public:
typedef asset_settle_operation operation_type;
@ -160,7 +160,7 @@ namespace graphene { namespace chain {
const asset_object* asset_to_settle = nullptr;
};
class asset_publish_feeds_evaluator : public evaluator<asset_publish_feeds_evaluator>
class asset_publish_feeds_evaluator : public fee_handling_evaluator<asset_publish_feeds_evaluator>
{
public:
typedef asset_publish_feed_operation operation_type;
@ -171,7 +171,7 @@ namespace graphene { namespace chain {
std::map<std::pair<asset_id_type,asset_id_type>,price_feed> median_feed_values;
};
class asset_claim_fees_evaluator : public evaluator<asset_claim_fees_evaluator>
class asset_claim_fees_evaluator : public fee_handling_evaluator<asset_claim_fees_evaluator>
{
public:
typedef asset_claim_fees_operation operation_type;

View file

@ -31,7 +31,7 @@
namespace graphene { namespace chain {
class balance_claim_evaluator : public evaluator<balance_claim_evaluator>
class balance_claim_evaluator : public fee_handling_evaluator<balance_claim_evaluator>
{
public:
typedef balance_claim_operation operation_type;

View file

@ -29,7 +29,7 @@
namespace graphene { namespace chain {
class betting_market_rules_create_evaluator : public evaluator<betting_market_rules_create_evaluator>
class betting_market_rules_create_evaluator : public fee_handling_evaluator<betting_market_rules_create_evaluator>
{
public:
typedef betting_market_rules_create_operation operation_type;
@ -38,7 +38,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const betting_market_rules_create_operation& o );
};
class betting_market_rules_update_evaluator : public evaluator<betting_market_rules_update_evaluator>
class betting_market_rules_update_evaluator : public fee_handling_evaluator<betting_market_rules_update_evaluator>
{
public:
typedef betting_market_rules_update_operation operation_type;
@ -49,7 +49,7 @@ namespace graphene { namespace chain {
const betting_market_rules_object* _rules;
};
class betting_market_group_create_evaluator : public evaluator<betting_market_group_create_evaluator>
class betting_market_group_create_evaluator : public fee_handling_evaluator<betting_market_group_create_evaluator>
{
public:
typedef betting_market_group_create_operation operation_type;
@ -61,7 +61,7 @@ namespace graphene { namespace chain {
betting_market_rules_id_type _rules_id;
};
class betting_market_group_update_evaluator : public evaluator<betting_market_group_update_evaluator>
class betting_market_group_update_evaluator : public fee_handling_evaluator<betting_market_group_update_evaluator>
{
public:
typedef betting_market_group_update_operation operation_type;
@ -73,7 +73,7 @@ namespace graphene { namespace chain {
const betting_market_group_object* _betting_market_group;
};
class betting_market_create_evaluator : public evaluator<betting_market_create_evaluator>
class betting_market_create_evaluator : public fee_handling_evaluator<betting_market_create_evaluator>
{
public:
typedef betting_market_create_operation operation_type;
@ -84,7 +84,7 @@ namespace graphene { namespace chain {
betting_market_group_id_type _group_id;
};
class betting_market_update_evaluator : public evaluator<betting_market_update_evaluator>
class betting_market_update_evaluator : public fee_handling_evaluator<betting_market_update_evaluator>
{
public:
typedef betting_market_update_operation operation_type;
@ -96,7 +96,7 @@ namespace graphene { namespace chain {
betting_market_group_id_type _group_id;
};
class bet_place_evaluator : public evaluator<bet_place_evaluator>
class bet_place_evaluator : public fee_handling_evaluator<bet_place_evaluator>
{
public:
typedef bet_place_operation operation_type;
@ -111,7 +111,7 @@ namespace graphene { namespace chain {
share_type _stake_plus_fees;
};
class bet_cancel_evaluator : public evaluator<bet_cancel_evaluator>
class bet_cancel_evaluator : public fee_handling_evaluator<bet_cancel_evaluator>
{
public:
typedef bet_cancel_operation operation_type;
@ -122,7 +122,7 @@ namespace graphene { namespace chain {
const bet_object* _bet_to_cancel;
};
class betting_market_group_resolve_evaluator : public evaluator<betting_market_group_resolve_evaluator>
class betting_market_group_resolve_evaluator : public fee_handling_evaluator<betting_market_group_resolve_evaluator>
{
public:
typedef betting_market_group_resolve_operation operation_type;
@ -133,7 +133,7 @@ namespace graphene { namespace chain {
const betting_market_group_object* _betting_market_group;
};
class betting_market_group_cancel_unmatched_bets_evaluator : public evaluator<betting_market_group_cancel_unmatched_bets_evaluator>
class betting_market_group_cancel_unmatched_bets_evaluator : public fee_handling_evaluator<betting_market_group_cancel_unmatched_bets_evaluator>
{
public:
typedef betting_market_group_cancel_unmatched_bets_operation operation_type;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class committee_member_create_evaluator : public evaluator<committee_member_create_evaluator>
class committee_member_create_evaluator : public fee_handling_evaluator<committee_member_create_evaluator>
{
public:
typedef committee_member_create_operation operation_type;
@ -37,7 +37,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const committee_member_create_operation& o );
};
class committee_member_update_evaluator : public evaluator<committee_member_update_evaluator>
class committee_member_update_evaluator : public fee_handling_evaluator<committee_member_update_evaluator>
{
public:
typedef committee_member_update_operation operation_type;
@ -46,7 +46,7 @@ namespace graphene { namespace chain {
void_result do_apply( const committee_member_update_operation& o );
};
class committee_member_update_global_parameters_evaluator : public evaluator<committee_member_update_global_parameters_evaluator>
class committee_member_update_global_parameters_evaluator : public fee_handling_evaluator<committee_member_update_global_parameters_evaluator>
{
public:
typedef committee_member_update_global_parameters_operation operation_type;

View file

@ -27,7 +27,7 @@
namespace graphene { namespace chain {
class transfer_to_blind_evaluator : public evaluator<transfer_to_blind_evaluator>
class transfer_to_blind_evaluator : public fee_handling_evaluator<transfer_to_blind_evaluator>
{
public:
typedef transfer_to_blind_operation operation_type;
@ -38,7 +38,7 @@ class transfer_to_blind_evaluator : public evaluator<transfer_to_blind_evaluator
virtual void pay_fee() override;
};
class transfer_from_blind_evaluator : public evaluator<transfer_from_blind_evaluator>
class transfer_from_blind_evaluator : public fee_handling_evaluator<transfer_from_blind_evaluator>
{
public:
typedef transfer_from_blind_operation operation_type;
@ -49,7 +49,7 @@ class transfer_from_blind_evaluator : public evaluator<transfer_from_blind_evalu
virtual void pay_fee() override;
};
class blind_transfer_evaluator : public evaluator<blind_transfer_evaluator>
class blind_transfer_evaluator : public fee_handling_evaluator<blind_transfer_evaluator>
{
public:
typedef blind_transfer_operation operation_type;

View file

@ -8,7 +8,7 @@ namespace graphene
namespace chain
{
class create_custom_account_authority_evaluator : public evaluator<create_custom_account_authority_evaluator>
class create_custom_account_authority_evaluator : public fee_handling_evaluator<create_custom_account_authority_evaluator>
{
public:
typedef custom_account_authority_create_operation operation_type;
@ -17,7 +17,7 @@ public:
object_id_type do_apply(const custom_account_authority_create_operation &o);
};
class update_custom_account_authority_evaluator : public evaluator<update_custom_account_authority_evaluator>
class update_custom_account_authority_evaluator : public fee_handling_evaluator<update_custom_account_authority_evaluator>
{
public:
typedef custom_account_authority_update_operation operation_type;
@ -26,7 +26,7 @@ public:
object_id_type do_apply(const custom_account_authority_update_operation &o);
};
class delete_custom_account_authority_evaluator : public evaluator<delete_custom_account_authority_evaluator>
class delete_custom_account_authority_evaluator : public fee_handling_evaluator<delete_custom_account_authority_evaluator>
{
public:
typedef custom_account_authority_delete_operation operation_type;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class custom_evaluator : public evaluator<custom_evaluator>
class custom_evaluator : public fee_handling_evaluator<custom_evaluator>
{
public:
typedef custom_operation operation_type;

View file

@ -9,7 +9,7 @@ namespace graphene
namespace chain
{
class create_custom_permission_evaluator : public evaluator<create_custom_permission_evaluator>
class create_custom_permission_evaluator : public fee_handling_evaluator<create_custom_permission_evaluator>
{
public:
typedef custom_permission_create_operation operation_type;
@ -18,7 +18,7 @@ public:
object_id_type do_apply(const custom_permission_create_operation &o);
};
class update_custom_permission_evaluator : public evaluator<update_custom_permission_evaluator>
class update_custom_permission_evaluator : public fee_handling_evaluator<update_custom_permission_evaluator>
{
public:
typedef custom_permission_update_operation operation_type;
@ -27,7 +27,7 @@ public:
object_id_type do_apply(const custom_permission_update_operation &o);
};
class delete_custom_permission_evaluator : public evaluator<delete_custom_permission_evaluator>
class delete_custom_permission_evaluator : public fee_handling_evaluator<delete_custom_permission_evaluator>
{
public:
typedef custom_permission_delete_operation operation_type;

View file

@ -347,52 +347,49 @@ namespace graphene { namespace chain {
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
* @brief Register a new third party evaluator to the evaluator chain for its operation type
* @tparam EvaluatorType An evaluator type which will be used to evaluate its declared operation type
* @return If registering an evaluator for an operation that already has an evaluator, returns a handle for
* the newly added evaluator which can be used to delete it later.
* @return Returns a handle for the newly added evaluator which can be used to delete it later.
*
* 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 registers a new third party evaluator type with the database. The evaluator specifies an
* operation type which it should be used to evaluate. A third party evaluator is an evaluator which belongs
* to code which is not part of official blockchain consensus. Consensus evaluators can only be added by the
* blockchain database itself. 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.
* registration. Values returned by third party evaluators will be ignored.
*
* The first evaluator registered for a given operation type is permanent, and is the only evaluator which
* can return a value. Subsequent (auxiliary) evaluators for that operation type can be deleted at runtime
* by calling @ref delete_evaluator() with the evaluator_handle obtained when registering the evaluator.
* IMPORTANT: Third party evaluators must observe certain rules of etiquette:
* - No exceptions. Exceptions indicate the operation is invalid, and only consensus code can declare an
* operation invalid. Third party evaluators should not throw exceptions.
* - No yielding. Evaluators run as part of the core consensus pathway, and must not yield, to preserve the
* guarantees of consistency of the database.
* - Fast execution. Evaluators must be quick. If heavy processing is necessary, defer it until after the
* core consensus pathway has finished execution.
*/
template<typename EvaluatorType>
optional<op_evaluator::evaluator_handle> register_evaluator()
op_evaluator::evaluator_handle register_third_party_evaluator()
{
auto& eval_ptr = _operation_evaluators[operation::tag<typename EvaluatorType::operation_type>::value];
if (eval_ptr == nullptr)
eval_ptr = std::make_unique<op_evaluator_impl<EvaluatorType>>();
else
return eval_ptr->append_evaluator(std::make_unique<op_evaluator_impl<EvaluatorType>>());
return {};
return register_evaluator<EvaluatorType, true>(_third_party_operation_evaluators);
}
/**
* @brief Delete an auxiliary evaluator
* @brief Delete a third party evaluator
* @param handle The evaluator handle for the evaluator to delete, as returned by @ref register_evaluator
*
* Auxiliary evaluators, or the second and subsequent evaluators registered for a given operation type,
* can be deleted so that they no longer execute when operations of the relevant type are processed.
* Third party evaluators, or evaluators registered by non-consensus code for a given operation type, can be
* deleted so that they no longer execute when operations of the relevant type are processed.
*
* If it may be desired to delete an auxiliary evaluator, retain the evaluator handle obtained when the
* evaluator was initially registered and when it is necessary to delete the evaluator, pass the handle
* to this function.
* If it may be desired to delete an evaluator, retain the evaluator handle obtained when the evaluator was
* initially registered and when it is necessary to delete the evaluator, pass the handle to this function.
*
* The evaluator will have been deleted by the time this function returns.
*/
void delete_evaluator(op_evaluator::evaluator_handle&& handle)
void delete_third_party_evaluator(op_evaluator::evaluator_handle&& handle)
{
if ((uint64_t)handle.get_operation_type() < _operation_evaluators.size())
_operation_evaluators[handle.get_operation_type()]->delete_evaluator(std::move(handle));
delete_evaluator(_third_party_operation_evaluators, std::move(handle));
}
//////////////////// db_balance.cpp ////////////////////
@ -553,7 +550,7 @@ namespace graphene { namespace chain {
*/
/// Enable or disable tracking of votes of standby witnesses and committee members
inline void enable_standby_votes_tracking(bool enable) { _track_standby_votes = enable; }
protected:
protected:
//Mark pop_undo() as protected -- we do not want outside calling pop_undo(); it should call pop_block() instead
void pop_undo() { object_database::pop_undo(); }
void notify_applied_block( const signed_block& block );
@ -562,14 +559,49 @@ namespace graphene { namespace chain {
private:
optional<undo_database::session> _pending_tx_session;
vector< unique_ptr<op_evaluator> > _operation_evaluators;
vector< unique_ptr<op_evaluator> > _third_party_operation_evaluators;
vector< unique_ptr<op_evaluator> > _consensus_operation_evaluators;
template<typename EvaluatorType, bool DiscardExceptions>
op_evaluator::evaluator_handle register_evaluator(vector<unique_ptr<op_evaluator>>& registry) {
auto op_tag = operation::tag<typename EvaluatorType::operation_type>::value;
FC_ASSERT(registry.size() > (size_t)op_tag,
"Cannot register evaluator for operation type ${T}: operation type is too large.",
("T", op_tag));
auto& eval_ptr = registry[op_tag];
if (eval_ptr == nullptr) {
eval_ptr = std::make_unique<op_evaluator_impl<EvaluatorType, DiscardExceptions>>();
return {eval_ptr.get(), op_tag};
} else {
auto new_evaluator = std::make_unique<op_evaluator_impl<EvaluatorType, DiscardExceptions>>();
return eval_ptr->append_evaluator(std::move(new_evaluator));
}
}
template<typename EvaluatorType>
op_evaluator::evaluator_handle register_consensus_evaluator() {
return register_evaluator<EvaluatorType, false>(_consensus_operation_evaluators);
}
void delete_evaluator(vector<unique_ptr<op_evaluator>>& registry, op_evaluator::evaluator_handle&& handle)
{
if ((uint64_t)handle.get_operation_type() < registry.size()) {
auto& eval_ptr = registry[handle.get_operation_type()];
if (eval_ptr.get() == handle.pointer)
eval_ptr = eval_ptr->take_next();
else
eval_ptr->delete_evaluator(std::move(handle));
}
}
void delete_consensus_evaluator(op_evaluator::evaluator_handle&& handle)
{
delete_evaluator(_consensus_operation_evaluators, std::move(handle));
}
template<class Index>
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
//////////////////// db_block.cpp ////////////////////
public:
public:
// these were formerly private, but they have a fairly well-defined API, so let's make them public
void apply_block( const signed_block& next_block, uint32_t skip = skip_nothing );
processed_transaction apply_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing );

View file

@ -29,17 +29,17 @@
namespace graphene { namespace chain {
class database;
class generic_evaluator;
class consensus_evaluator;
class transaction_evaluation_state;
class account_object;
class account_statistics_object;
class asset_object;
class asset_dynamic_data_object;
class generic_evaluator
class consensus_evaluator
{
public:
virtual ~generic_evaluator(){}
virtual ~consensus_evaluator(){}
virtual int get_type()const = 0;
virtual operation_result start_evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply);
@ -132,8 +132,9 @@ namespace graphene { namespace chain {
evaluator_handle(const evaluator_handle&) = delete;
evaluator_handle& operator=(const evaluator_handle&) = delete;
friend class database;
friend class op_evaluator;
template<typename>
template<typename, bool>
friend class op_evaluator_impl;
// Pointer to the handled evaluator
@ -150,17 +151,22 @@ namespace graphene { namespace chain {
virtual ~op_evaluator(){}
virtual evaluator_handle append_evaluator(unique_ptr<op_evaluator> next_evaluator) = 0;
std::unique_ptr<op_evaluator> take_next() { return std::move(next_evaluator); }
virtual void delete_evaluator(evaluator_handle&& handle) {
FC_ASSERT(handle.pointer != this, "Cannot delete first element of evaluator chain!");
if (next_evaluator.get() == handle.pointer)
// Next evaluator in chain is the one to delete. Move its next pointer into ours, and unique_ptr will delete the one that's going away.
next_evaluator = std::move(next_evaluator->next_evaluator);
else
next_evaluator = next_evaluator->take_next();
else if (next_evaluator != nullptr)
next_evaluator->delete_evaluator(std::move(handle));
else
elog("ERROR: Attempted to delete evaluator, but did not find referenced evaluator in the chain");
}
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) = 0;
};
template<typename T>
template<typename T, bool DiscardExceptions>
class op_evaluator_impl : public op_evaluator
{
public:
@ -174,16 +180,30 @@ namespace graphene { namespace chain {
}
virtual operation_result evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply = true) override
{
T eval;
auto result = eval.start_evaluate(eval_state, op, apply);
operation_result result;
try {
T eval;
result = eval.start_evaluate(eval_state, op, apply);
} catch (fc::exception_ptr e) {
if (DiscardExceptions)
elog("ERROR: Third party evaluator threw an exception. Discarding.", ("exception", e));
else
throw;
} catch (...) {
if (DiscardExceptions)
elog("ERROR: Third party evaluator threw an unknown exception type. Discarding.");
else
throw;
}
if (this->next_evaluator != nullptr)
this->next_evaluator->evaluate(eval_state, op, apply);
this->next_evaluator->evaluate(eval_state, op, apply);
return result;
}
};
template<typename DerivedEvaluator>
class evaluator : public generic_evaluator
class fee_handling_evaluator : public consensus_evaluator
{
public:
virtual int get_type()const override { return operation::tag<typename DerivedEvaluator::operation_type>::value; }
@ -221,4 +241,32 @@ namespace graphene { namespace chain {
return result;
}
};
template<typename DerivedEvaluator>
class third_party_evaluator {
protected:
transaction_evaluation_state* trx_state = nullptr;
database& db() {
FC_ASSERT(trx_state != nullptr, "Cannot get database: evaluator not initialized");
return trx_state->db();
}
public:
operation_result start_evaluate(transaction_evaluation_state& eval_state, const operation& op, bool apply) {
trx_state = &eval_state;
using Operation = typename DerivedEvaluator::operation_type;
Operation specific_operation = op.get<Operation>();
DerivedEvaluator& specific_evaluator = static_cast<DerivedEvaluator&>(*this);
operation_result result;
result = specific_evaluator.do_evaluate(specific_operation);
if (apply)
result = specific_evaluator.do_apply(specific_operation);
return result;
}
};
} }

View file

@ -31,7 +31,7 @@
namespace graphene { namespace chain {
class event_create_evaluator : public evaluator<event_create_evaluator>
class event_create_evaluator : public fee_handling_evaluator<event_create_evaluator>
{
public:
typedef event_create_operation operation_type;
@ -42,7 +42,7 @@ namespace graphene { namespace chain {
event_group_id_type event_group_id;
};
class event_update_evaluator : public evaluator<event_update_evaluator>
class event_update_evaluator : public fee_handling_evaluator<event_update_evaluator>
{
public:
typedef event_update_operation operation_type;
@ -53,7 +53,7 @@ namespace graphene { namespace chain {
event_group_id_type event_group_id;
};
class event_update_status_evaluator : public evaluator<event_update_status_evaluator>
class event_update_status_evaluator : public fee_handling_evaluator<event_update_status_evaluator>
{
public:
typedef event_update_status_operation operation_type;

View file

@ -31,7 +31,7 @@ namespace graphene { namespace chain {
class event_group_object;
class event_group_create_evaluator : public evaluator<event_group_create_evaluator>
class event_group_create_evaluator : public fee_handling_evaluator<event_group_create_evaluator>
{
public:
typedef event_group_create_operation operation_type;
@ -43,7 +43,7 @@ namespace graphene { namespace chain {
sport_id_type sport_id;
};
class event_group_update_evaluator : public evaluator<event_group_update_evaluator>
class event_group_update_evaluator : public fee_handling_evaluator<event_group_update_evaluator>
{
public:
typedef event_group_update_operation operation_type;
@ -55,7 +55,7 @@ namespace graphene { namespace chain {
sport_id_type sport_id;
};
class event_group_delete_evaluator : public evaluator<event_group_delete_evaluator>
class event_group_delete_evaluator : public fee_handling_evaluator<event_group_delete_evaluator>
{
public:
typedef event_group_delete_operation operation_type;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class ticket_purchase_evaluator : public evaluator<ticket_purchase_evaluator>
class ticket_purchase_evaluator : public fee_handling_evaluator<ticket_purchase_evaluator>
{
public:
typedef ticket_purchase_operation operation_type;
@ -40,7 +40,7 @@ namespace graphene { namespace chain {
const asset_dynamic_data_object* asset_dynamic_data;
};
class lottery_reward_evaluator : public evaluator<lottery_reward_evaluator>
class lottery_reward_evaluator : public fee_handling_evaluator<lottery_reward_evaluator>
{
public:
typedef lottery_reward_operation operation_type;
@ -52,7 +52,7 @@ namespace graphene { namespace chain {
const asset_dynamic_data_object* asset_dynamic_data;
};
class lottery_end_evaluator : public evaluator<lottery_end_evaluator>
class lottery_end_evaluator : public fee_handling_evaluator<lottery_end_evaluator>
{
public:
typedef lottery_end_operation operation_type;
@ -64,7 +64,7 @@ namespace graphene { namespace chain {
const asset_dynamic_data_object* asset_dynamic_data;
};
class sweeps_vesting_claim_evaluator : public evaluator<sweeps_vesting_claim_evaluator>
class sweeps_vesting_claim_evaluator : public fee_handling_evaluator<sweeps_vesting_claim_evaluator>
{
public:
typedef sweeps_vesting_claim_operation operation_type;

View file

@ -33,7 +33,7 @@ namespace graphene { namespace chain {
class call_order_object;
class limit_order_object;
class limit_order_create_evaluator : public evaluator<limit_order_create_evaluator>
class limit_order_create_evaluator : public fee_handling_evaluator<limit_order_create_evaluator>
{
public:
typedef limit_order_create_operation operation_type;
@ -55,7 +55,7 @@ namespace graphene { namespace chain {
const asset_object* _receive_asset = nullptr;
};
class limit_order_cancel_evaluator : public evaluator<limit_order_cancel_evaluator>
class limit_order_cancel_evaluator : public fee_handling_evaluator<limit_order_cancel_evaluator>
{
public:
typedef limit_order_cancel_operation operation_type;
@ -66,7 +66,7 @@ namespace graphene { namespace chain {
const limit_order_object* _order;
};
class call_order_update_evaluator : public evaluator<call_order_update_evaluator>
class call_order_update_evaluator : public fee_handling_evaluator<call_order_update_evaluator>
{
public:
typedef call_order_update_operation operation_type;

View file

@ -8,7 +8,7 @@
namespace graphene { namespace chain {
class nft_metadata_create_evaluator : public evaluator<nft_metadata_create_evaluator>
class nft_metadata_create_evaluator : public fee_handling_evaluator<nft_metadata_create_evaluator>
{
public:
typedef nft_metadata_create_operation operation_type;
@ -16,7 +16,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const nft_metadata_create_operation& o );
};
class nft_metadata_update_evaluator : public evaluator<nft_metadata_update_evaluator>
class nft_metadata_update_evaluator : public fee_handling_evaluator<nft_metadata_update_evaluator>
{
public:
typedef nft_metadata_update_operation operation_type;
@ -24,7 +24,7 @@ namespace graphene { namespace chain {
void_result do_apply( const nft_metadata_update_operation& o );
};
class nft_mint_evaluator : public evaluator<nft_mint_evaluator>
class nft_mint_evaluator : public fee_handling_evaluator<nft_mint_evaluator>
{
public:
typedef nft_mint_operation operation_type;
@ -32,7 +32,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const nft_mint_operation& o );
};
class nft_safe_transfer_from_evaluator : public evaluator<nft_safe_transfer_from_evaluator>
class nft_safe_transfer_from_evaluator : public fee_handling_evaluator<nft_safe_transfer_from_evaluator>
{
public:
typedef nft_safe_transfer_from_operation operation_type;
@ -40,7 +40,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const nft_safe_transfer_from_operation& o );
};
class nft_approve_evaluator : public evaluator<nft_approve_evaluator>
class nft_approve_evaluator : public fee_handling_evaluator<nft_approve_evaluator>
{
public:
typedef nft_approve_operation operation_type;
@ -48,7 +48,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const nft_approve_operation& o );
};
class nft_set_approval_for_all_evaluator : public evaluator<nft_set_approval_for_all_evaluator>
class nft_set_approval_for_all_evaluator : public fee_handling_evaluator<nft_set_approval_for_all_evaluator>
{
public:
typedef nft_set_approval_for_all_operation operation_type;

View file

@ -10,7 +10,7 @@ namespace graphene
namespace chain
{
class nft_lottery_token_purchase_evaluator : public evaluator<nft_lottery_token_purchase_evaluator>
class nft_lottery_token_purchase_evaluator : public fee_handling_evaluator<nft_lottery_token_purchase_evaluator>
{
public:
typedef nft_lottery_token_purchase_operation operation_type;
@ -19,7 +19,7 @@ namespace graphene
object_id_type do_apply(const nft_lottery_token_purchase_operation &o);
};
class nft_lottery_reward_evaluator : public evaluator<nft_lottery_reward_evaluator>
class nft_lottery_reward_evaluator : public fee_handling_evaluator<nft_lottery_reward_evaluator>
{
public:
typedef nft_lottery_reward_operation operation_type;
@ -28,7 +28,7 @@ namespace graphene
void_result do_apply(const nft_lottery_reward_operation &o);
};
class nft_lottery_end_evaluator : public evaluator<nft_lottery_end_evaluator>
class nft_lottery_end_evaluator : public fee_handling_evaluator<nft_lottery_end_evaluator>
{
public:
typedef nft_lottery_end_operation operation_type;

View file

@ -8,7 +8,7 @@ namespace graphene
namespace chain
{
class offer_evaluator : public evaluator<offer_evaluator>
class offer_evaluator : public fee_handling_evaluator<offer_evaluator>
{
public:
typedef offer_operation operation_type;
@ -17,7 +17,7 @@ namespace graphene
object_id_type do_apply(const offer_operation &o);
};
class bid_evaluator : public evaluator<bid_evaluator>
class bid_evaluator : public fee_handling_evaluator<bid_evaluator>
{
public:
typedef bid_operation operation_type;
@ -26,7 +26,7 @@ namespace graphene
void_result do_apply(const bid_operation &o);
};
class cancel_offer_evaluator : public evaluator<cancel_offer_evaluator>
class cancel_offer_evaluator : public fee_handling_evaluator<cancel_offer_evaluator>
{
public:
typedef cancel_offer_operation operation_type;
@ -35,7 +35,7 @@ namespace graphene
void_result do_apply(const cancel_offer_operation &o);
};
class finalize_offer_evaluator : public evaluator<finalize_offer_evaluator>
class finalize_offer_evaluator : public fee_handling_evaluator<finalize_offer_evaluator>
{
public:
typedef finalize_offer_operation operation_type;

View file

@ -46,7 +46,7 @@ namespace graphene { namespace chain {
void operator()( const son_report_down_operation &v );
};
class proposal_create_evaluator : public evaluator<proposal_create_evaluator>
class proposal_create_evaluator : public fee_handling_evaluator<proposal_create_evaluator>
{
public:
typedef proposal_create_operation operation_type;
@ -57,7 +57,7 @@ namespace graphene { namespace chain {
transaction _proposed_trx;
};
class proposal_update_evaluator : public evaluator<proposal_update_evaluator>
class proposal_update_evaluator : public fee_handling_evaluator<proposal_update_evaluator>
{
public:
typedef proposal_update_operation operation_type;
@ -71,7 +71,7 @@ namespace graphene { namespace chain {
bool _proposal_failed = false;
};
class proposal_delete_evaluator : public evaluator<proposal_delete_evaluator>
class proposal_delete_evaluator : public fee_handling_evaluator<proposal_delete_evaluator>
{
public:
typedef proposal_delete_operation operation_type;

View file

@ -7,7 +7,7 @@
namespace graphene { namespace chain {
class random_number_store_evaluator : public evaluator<random_number_store_evaluator>
class random_number_store_evaluator : public fee_handling_evaluator<random_number_store_evaluator>
{
public:
typedef random_number_store_operation operation_type;

View file

@ -5,7 +5,7 @@
namespace graphene { namespace chain {
class add_sidechain_address_evaluator : public evaluator<add_sidechain_address_evaluator>
class add_sidechain_address_evaluator : public fee_handling_evaluator<add_sidechain_address_evaluator>
{
public:
typedef sidechain_address_add_operation operation_type;
@ -14,7 +14,7 @@ public:
object_id_type do_apply(const sidechain_address_add_operation& o);
};
class update_sidechain_address_evaluator : public evaluator<update_sidechain_address_evaluator>
class update_sidechain_address_evaluator : public fee_handling_evaluator<update_sidechain_address_evaluator>
{
public:
typedef sidechain_address_update_operation operation_type;
@ -23,7 +23,7 @@ public:
object_id_type do_apply(const sidechain_address_update_operation& o);
};
class delete_sidechain_address_evaluator : public evaluator<delete_sidechain_address_evaluator>
class delete_sidechain_address_evaluator : public fee_handling_evaluator<delete_sidechain_address_evaluator>
{
public:
typedef sidechain_address_delete_operation operation_type;

View file

@ -5,7 +5,7 @@
namespace graphene { namespace chain {
class sidechain_transaction_create_evaluator : public evaluator<sidechain_transaction_create_evaluator>
class sidechain_transaction_create_evaluator : public fee_handling_evaluator<sidechain_transaction_create_evaluator>
{
public:
typedef sidechain_transaction_create_operation operation_type;
@ -14,7 +14,7 @@ public:
object_id_type do_apply(const sidechain_transaction_create_operation& o);
};
class sidechain_transaction_sign_evaluator : public evaluator<sidechain_transaction_sign_evaluator>
class sidechain_transaction_sign_evaluator : public fee_handling_evaluator<sidechain_transaction_sign_evaluator>
{
public:
typedef sidechain_transaction_sign_operation operation_type;
@ -23,7 +23,7 @@ public:
object_id_type do_apply(const sidechain_transaction_sign_operation& o);
};
class sidechain_transaction_send_evaluator : public evaluator<sidechain_transaction_send_evaluator>
class sidechain_transaction_send_evaluator : public fee_handling_evaluator<sidechain_transaction_send_evaluator>
{
public:
typedef sidechain_transaction_send_operation operation_type;
@ -32,7 +32,7 @@ public:
object_id_type do_apply(const sidechain_transaction_send_operation& o);
};
class sidechain_transaction_settle_evaluator : public evaluator<sidechain_transaction_settle_evaluator>
class sidechain_transaction_settle_evaluator : public fee_handling_evaluator<sidechain_transaction_settle_evaluator>
{
public:
typedef sidechain_transaction_settle_operation operation_type;

View file

@ -5,7 +5,7 @@
namespace graphene { namespace chain {
class create_son_evaluator : public evaluator<create_son_evaluator>
class create_son_evaluator : public fee_handling_evaluator<create_son_evaluator>
{
public:
typedef son_create_operation operation_type;
@ -14,7 +14,7 @@ public:
object_id_type do_apply(const son_create_operation& o);
};
class update_son_evaluator : public evaluator<update_son_evaluator>
class update_son_evaluator : public fee_handling_evaluator<update_son_evaluator>
{
public:
typedef son_update_operation operation_type;
@ -23,7 +23,7 @@ public:
object_id_type do_apply(const son_update_operation& o);
};
class deregister_son_evaluator : public evaluator<deregister_son_evaluator>
class deregister_son_evaluator : public fee_handling_evaluator<deregister_son_evaluator>
{
public:
typedef son_deregister_operation operation_type;
@ -32,7 +32,7 @@ public:
void_result do_apply(const son_deregister_operation& o);
};
class son_heartbeat_evaluator : public evaluator<son_heartbeat_evaluator>
class son_heartbeat_evaluator : public fee_handling_evaluator<son_heartbeat_evaluator>
{
public:
typedef son_heartbeat_operation operation_type;
@ -41,7 +41,7 @@ public:
object_id_type do_apply(const son_heartbeat_operation& o);
};
class son_report_down_evaluator : public evaluator<son_report_down_evaluator>
class son_report_down_evaluator : public fee_handling_evaluator<son_report_down_evaluator>
{
public:
typedef son_report_down_operation operation_type;
@ -50,7 +50,7 @@ public:
object_id_type do_apply(const son_report_down_operation& o);
};
class son_maintenance_evaluator : public evaluator<son_maintenance_evaluator>
class son_maintenance_evaluator : public fee_handling_evaluator<son_maintenance_evaluator>
{
public:
typedef son_maintenance_operation operation_type;

View file

@ -3,7 +3,7 @@
namespace graphene { namespace chain {
class create_son_wallet_deposit_evaluator : public evaluator<create_son_wallet_deposit_evaluator>
class create_son_wallet_deposit_evaluator : public fee_handling_evaluator<create_son_wallet_deposit_evaluator>
{
public:
typedef son_wallet_deposit_create_operation operation_type;
@ -12,7 +12,7 @@ public:
object_id_type do_apply(const son_wallet_deposit_create_operation& o);
};
class process_son_wallet_deposit_evaluator : public evaluator<process_son_wallet_deposit_evaluator>
class process_son_wallet_deposit_evaluator : public fee_handling_evaluator<process_son_wallet_deposit_evaluator>
{
public:
typedef son_wallet_deposit_process_operation operation_type;

View file

@ -4,7 +4,7 @@
namespace graphene { namespace chain {
class recreate_son_wallet_evaluator : public evaluator<recreate_son_wallet_evaluator>
class recreate_son_wallet_evaluator : public fee_handling_evaluator<recreate_son_wallet_evaluator>
{
public:
typedef son_wallet_recreate_operation operation_type;
@ -13,7 +13,7 @@ public:
object_id_type do_apply(const son_wallet_recreate_operation& o);
};
class update_son_wallet_evaluator : public evaluator<update_son_wallet_evaluator>
class update_son_wallet_evaluator : public fee_handling_evaluator<update_son_wallet_evaluator>
{
public:
typedef son_wallet_update_operation operation_type;

View file

@ -3,7 +3,7 @@
namespace graphene { namespace chain {
class create_son_wallet_withdraw_evaluator : public evaluator<create_son_wallet_withdraw_evaluator>
class create_son_wallet_withdraw_evaluator : public fee_handling_evaluator<create_son_wallet_withdraw_evaluator>
{
public:
typedef son_wallet_withdraw_create_operation operation_type;
@ -12,7 +12,7 @@ public:
object_id_type do_apply(const son_wallet_withdraw_create_operation& o);
};
class process_son_wallet_withdraw_evaluator : public evaluator<process_son_wallet_withdraw_evaluator>
class process_son_wallet_withdraw_evaluator : public fee_handling_evaluator<process_son_wallet_withdraw_evaluator>
{
public:
typedef son_wallet_withdraw_process_operation operation_type;

View file

@ -31,7 +31,7 @@ namespace graphene { namespace chain {
class sport_object;
class sport_create_evaluator : public evaluator<sport_create_evaluator>
class sport_create_evaluator : public fee_handling_evaluator<sport_create_evaluator>
{
public:
typedef sport_create_operation operation_type;
@ -40,7 +40,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const sport_create_operation& o );
};
class sport_update_evaluator : public evaluator<sport_update_evaluator>
class sport_update_evaluator : public fee_handling_evaluator<sport_update_evaluator>
{
public:
typedef sport_update_operation operation_type;
@ -49,7 +49,7 @@ namespace graphene { namespace chain {
void_result do_apply( const sport_update_operation& o );
};
class sport_delete_evaluator : public evaluator<sport_delete_evaluator>
class sport_delete_evaluator : public fee_handling_evaluator<sport_delete_evaluator>
{
public:
typedef sport_delete_operation operation_type;

View file

@ -5,7 +5,7 @@
namespace graphene { namespace chain {
class tournament_create_evaluator : public evaluator<tournament_create_evaluator>
class tournament_create_evaluator : public fee_handling_evaluator<tournament_create_evaluator>
{
public:
typedef tournament_create_operation operation_type;
@ -14,7 +14,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const tournament_create_operation& o );
};
class tournament_join_evaluator : public evaluator<tournament_join_evaluator>
class tournament_join_evaluator : public fee_handling_evaluator<tournament_join_evaluator>
{
private:
const tournament_object* _tournament_obj = nullptr;
@ -28,7 +28,7 @@ namespace graphene { namespace chain {
void_result do_apply( const tournament_join_operation& o );
};
class tournament_leave_evaluator : public evaluator<tournament_leave_evaluator>
class tournament_leave_evaluator : public fee_handling_evaluator<tournament_leave_evaluator>
{
private:
const tournament_object* _tournament_obj = nullptr;
@ -40,7 +40,7 @@ namespace graphene { namespace chain {
void_result do_apply( const tournament_leave_operation& o );
};
class game_move_evaluator : public evaluator<game_move_evaluator>
class game_move_evaluator : public fee_handling_evaluator<game_move_evaluator>
{
private:
const game_object* _game_obj = nullptr;

View file

@ -28,7 +28,7 @@
namespace graphene { namespace chain {
class transfer_evaluator : public evaluator<transfer_evaluator>
class transfer_evaluator : public fee_handling_evaluator<transfer_evaluator>
{
public:
typedef transfer_operation operation_type;
@ -37,7 +37,7 @@ namespace graphene { namespace chain {
void_result do_apply( const transfer_operation& o );
};
class override_transfer_evaluator : public evaluator<override_transfer_evaluator>
class override_transfer_evaluator : public fee_handling_evaluator<override_transfer_evaluator>
{
public:
typedef override_transfer_operation operation_type;

View file

@ -30,7 +30,7 @@ namespace graphene { namespace chain {
class vesting_balance_create_evaluator;
class vesting_balance_withdraw_evaluator;
class vesting_balance_create_evaluator : public evaluator<vesting_balance_create_evaluator>
class vesting_balance_create_evaluator : public fee_handling_evaluator<vesting_balance_create_evaluator>
{
public:
typedef vesting_balance_create_operation operation_type;
@ -39,7 +39,7 @@ class vesting_balance_create_evaluator : public evaluator<vesting_balance_create
object_id_type do_apply( const vesting_balance_create_operation& op );
};
class vesting_balance_withdraw_evaluator : public evaluator<vesting_balance_withdraw_evaluator>
class vesting_balance_withdraw_evaluator : public fee_handling_evaluator<vesting_balance_withdraw_evaluator>
{
public:
typedef vesting_balance_withdraw_operation operation_type;

View file

@ -27,7 +27,7 @@
namespace graphene { namespace chain {
class withdraw_permission_create_evaluator : public evaluator<withdraw_permission_create_evaluator>
class withdraw_permission_create_evaluator : public fee_handling_evaluator<withdraw_permission_create_evaluator>
{
public:
typedef withdraw_permission_create_operation operation_type;
@ -36,7 +36,7 @@ public:
object_id_type do_apply( const operation_type& op );
};
class withdraw_permission_claim_evaluator : public evaluator<withdraw_permission_claim_evaluator>
class withdraw_permission_claim_evaluator : public fee_handling_evaluator<withdraw_permission_claim_evaluator>
{
public:
typedef withdraw_permission_claim_operation operation_type;
@ -45,7 +45,7 @@ public:
void_result do_apply( const operation_type& op );
};
class withdraw_permission_update_evaluator : public evaluator<withdraw_permission_update_evaluator>
class withdraw_permission_update_evaluator : public fee_handling_evaluator<withdraw_permission_update_evaluator>
{
public:
typedef withdraw_permission_update_operation operation_type;
@ -54,7 +54,7 @@ public:
void_result do_apply( const operation_type& op );
};
class withdraw_permission_delete_evaluator : public evaluator<withdraw_permission_delete_evaluator>
class withdraw_permission_delete_evaluator : public fee_handling_evaluator<withdraw_permission_delete_evaluator>
{
public:
typedef withdraw_permission_delete_operation operation_type;

View file

@ -27,7 +27,7 @@
namespace graphene { namespace chain {
class witness_create_evaluator : public evaluator<witness_create_evaluator>
class witness_create_evaluator : public fee_handling_evaluator<witness_create_evaluator>
{
public:
typedef witness_create_operation operation_type;
@ -36,7 +36,7 @@ namespace graphene { namespace chain {
object_id_type do_apply( const witness_create_operation& o );
};
class witness_update_evaluator : public evaluator<witness_update_evaluator>
class witness_update_evaluator : public fee_handling_evaluator<witness_update_evaluator>
{
public:
typedef witness_update_operation operation_type;

View file

@ -26,7 +26,7 @@
namespace graphene { namespace chain {
class worker_create_evaluator : public evaluator<worker_create_evaluator>
class worker_create_evaluator : public fee_handling_evaluator<worker_create_evaluator>
{
public:
typedef worker_create_operation operation_type;

View file

@ -69,7 +69,7 @@ void_result limit_order_create_evaluator::do_evaluate(const limit_order_create_o
void limit_order_create_evaluator::pay_fee()
{
if( db().head_block_time() <= HARDFORK_445_TIME )
generic_evaluator::pay_fee();
consensus_evaluator::pay_fee();
else
_deferred_fee = core_fee_paid;
}

View file

@ -0,0 +1,129 @@
/*
* Copyright (c) 2015 Cryptonomex, Inc., and contributors.
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <boost/test/unit_test.hpp>
#include <graphene/chain/database.hpp>
#include "../common/database_fixture.hpp"
using namespace graphene::chain;
using namespace graphene::chain::test;
static std::string evaluators_ran;
template<int discriminant>
class test_evaluator : public third_party_evaluator<test_evaluator<discriminant>>
{
public:
using operation_type = custom_operation;
operation_result do_evaluate(const custom_operation&) {
evaluators_ran += std::to_string(discriminant);
return {};
}
operation_result do_apply(const custom_operation&) { return {}; }
};
BOOST_AUTO_TEST_SUITE(evaluator_tests)
BOOST_FIXTURE_TEST_CASE(evaluator_chain, database_fixture)
{ try {
// Required because custom_operation uses old fee > 0 check rather than fee >= 0 check... Fees required.
enable_fees();
// Create an account and give him tokens
ACTORS((nathaniel));
transfer(account_id_type(), nathaniel_id, asset(1000000));
generate_block();
// Create 4 different third party evaluators on custom operation
auto handle_0 = db.register_third_party_evaluator<test_evaluator<0>>();
auto handle_1 = db.register_third_party_evaluator<test_evaluator<1>>();
auto handle_2 = db.register_third_party_evaluator<test_evaluator<2>>();
auto handle_3 = db.register_third_party_evaluator<test_evaluator<3>>();
// Run a custom operation
custom_operation op;
op.payer = nathaniel_id;
op.fee.amount.value =
op.calculate_fee(db.get_global_properties().parameters.current_fees->get<custom_operation>()).value;
signed_transaction trx;
trx.operations = {op};
test::set_expiration(db, trx);
sign(trx, nathaniel_private_key);
db.push_transaction(trx);
// Check that all 4 evaluators ran, and reset record
BOOST_CHECK_EQUAL(evaluators_ran, "0123");
evaluators_ran.clear();
// Delete second evaluator in chain
db.delete_third_party_evaluator(std::move(handle_1));
// Run again and verify proper evaluator sequence
trx.expiration += 1;
trx.clear_signatures();
sign(trx, nathaniel_private_key);
db.push_transaction(trx);
BOOST_CHECK_EQUAL(evaluators_ran, "023");
evaluators_ran.clear();
// Delete first evaluator in chain
db.delete_third_party_evaluator(std::move(handle_0));
// Run again and verify proper evaluator sequence
trx.expiration += 1;
trx.clear_signatures();
sign(trx, nathaniel_private_key);
db.push_transaction(trx);
BOOST_CHECK_EQUAL(evaluators_ran, "23");
evaluators_ran.clear();
// Delete last evaluator in chain
db.delete_third_party_evaluator(std::move(handle_3));
// Run again and verify proper evaluator sequence
trx.expiration += 1;
trx.clear_signatures();
sign(trx, nathaniel_private_key);
db.push_transaction(trx);
BOOST_CHECK_EQUAL(evaluators_ran, "2");
evaluators_ran.clear();
// Delete only evaluator in chain
db.delete_third_party_evaluator(std::move(handle_2));
// Run again and verify none of our evaluators ran
trx.expiration += 1;
trx.clear_signatures();
sign(trx, nathaniel_private_key);
db.push_transaction(trx);
BOOST_TEST_CHECK(evaluators_ran.empty());
BOOST_CHECK_EQUAL(db.get_balance(nathaniel_id, asset_id_type()).amount.value, (1000000 - op.fee.amount*5).value);
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_SUITE_END()