diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 03ed332f..a0d88024 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -108,6 +108,17 @@ object_id_type account_create_evaluator::do_apply( const account_create_operatio obj.options.memo_key = get_relative_id(obj.options.memo_key); }); + const auto& global_properties = db().get_global_properties(); + const auto& dynamic_properties = db().get_dynamic_global_properties(); + db().modify(dynamic_properties, [](dynamic_global_property_object& p) { + ++p.accounts_registered_this_interval; + }); + if( dynamic_properties.accounts_registered_this_interval % + global_properties.parameters.accounts_per_fee_scale == 0 ) + db().modify(global_properties, [&dynamic_properties](global_property_object& p) { + p.parameters.current_fees.account_create_fee <<= p.parameters.account_fee_scale_bitshifts; + }); + return new_acnt_object.id; } FC_CAPTURE_AND_RETHROW((o)) } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 11bc6770..3840b705 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -429,11 +429,18 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g update_active_witnesses(); update_active_delegates(); - if( gpo.pending_parameters ) - modify(gpo, [](global_property_object& p) { + modify(gpo, [this](global_property_object& p) { + // Remove scaling of account registration fee + const auto& dgpo = get_dynamic_global_properties(); + p.parameters.current_fees.account_create_fee >>= p.parameters.account_fee_scale_bitshifts * + (dgpo.accounts_registered_this_interval / p.parameters.accounts_per_fee_scale); + + if( p.pending_parameters ) + { p.parameters = std::move(*p.pending_parameters); p.pending_parameters.reset(); - }); + } + }); auto new_block_interval = global_props.parameters.block_interval; @@ -445,7 +452,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g if( !r ) { _pending_block.timestamp -= r; - assert( (_pending_block.timestamp.sec_since_epoch() % new_block_interval) == 0 ); + assert( (_pending_block.timestamp.sec_since_epoch() % new_block_interval) == 0 ); } auto next_maintenance_time = get(dynamic_global_property_id_type()).next_maintenance_time; @@ -465,6 +472,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g modify(get_dynamic_global_properties(), [next_maintenance_time](dynamic_global_property_object& d) { d.next_maintenance_time = next_maintenance_time; + d.accounts_registered_this_interval = 0; }); // Reset all BitAsset force settlement volumes to zero diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index dc875d66..b1e181b2 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -93,6 +93,8 @@ #define GRAPHENE_WITNESS_PAY_PERCENT_PRECISION (1000000000) #define GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE 1 #define GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD GRAPHENE_BLOCKCHAIN_PRECISION * 100; +#define GRAPHENE_DEFAULT_ACCOUNTS_PER_FEE_SCALE 1000 +#define GRAPHENE_DEFAULT_ACCOUNT_FEE_SCALE_BITSHIFTS 4 #define GRAPHENE_GENESIS_TIMESTAMP (1431700000) /// Should be divisible by GRAPHENE_DEFAULT_BLOCK_INTERVAL #define GRAPHENE_MAX_WORKER_NAME_LENGTH 63 diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index c69a9169..ee7e53c5 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -76,10 +76,10 @@ namespace graphene { namespace chain { time_point_sec next_maintenance_time; time_point_sec last_budget_time; share_type witness_budget; + uint32_t accounts_registered_this_interval; }; }} - FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object), (random) (head_block_number) @@ -88,6 +88,7 @@ FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene:: (current_witness) (next_maintenance_time) (witness_budget) + (accounts_registered_this_interval) ) FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::object), diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index 13669f77..ab99b20b 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -345,7 +345,7 @@ namespace graphene { namespace chain { } uint32_t key_create_fee = 270300; ///< the cost to register a public key with the blockchain - uint32_t account_create_fee = 666666; ///< the cost to register the cheapest non-free account + uint64_t account_create_fee = 666666; ///< the cost to register the cheapest non-free account uint32_t account_update_fee = 150000; ///< the cost to update an existing account uint32_t account_transfer_fee = 300000; ///< the cost to transfer an account to a new owner uint32_t account_whitelist_fee = 300000; ///< the fee to whitelist an account @@ -457,6 +457,8 @@ namespace graphene { namespace chain { share_type worker_budget_per_day = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; ///< CORE to be allocated to workers (per day) uint16_t max_predicate_opcode = GRAPHENE_DEFAULT_MAX_ASSERT_OPCODE; ///< predicate_opcode must be less than this number share_type fee_liquidation_threshold = GRAPHENE_DEFAULT_FEE_LIQUIDATION_THRESHOLD; ///< value in CORE at which accumulated fees in blockchain-issued market assets should be liquidated + uint16_t accounts_per_fee_scale = GRAPHENE_DEFAULT_ACCOUNTS_PER_FEE_SCALE; ///< number of accounts between fee scalings + uint8_t account_fee_scale_bitshifts = GRAPHENE_DEFAULT_ACCOUNT_FEE_SCALE_BITSHIFTS; ///< number of times to left bitshift account registration fee at each scaling void validate()const { @@ -616,6 +618,8 @@ FC_REFLECT( graphene::chain::chain_parameters, (worker_budget_per_day) (max_predicate_opcode) (fee_liquidation_threshold) + (accounts_per_fee_scale) + (account_fee_scale_bitshifts) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index eb4adefd..f838dc34 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -839,4 +839,27 @@ BOOST_FIXTURE_TEST_CASE( witness_scheduler_missed_blocks, database_fixture ) }); } FC_LOG_AND_RETHROW() } +BOOST_FIXTURE_TEST_CASE( account_create_fee_scaling, database_fixture ) +{ try { + auto accounts_per_scale = db.get_global_properties().parameters.accounts_per_fee_scale; + enable_fees(1); + + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); + for( int i = db.get_dynamic_global_properties().accounts_registered_this_interval; i < accounts_per_scale; ++i ) + create_account("shill" + fc::to_string(i)); + generate_block(); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 16); + for( int i = 0; i < accounts_per_scale; ++i ) + create_account("moreshills" + fc::to_string(i)); + generate_block(); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 256); + for( int i = 0; i < accounts_per_scale; ++i ) + create_account("moarshills" + fc::to_string(i)); + generate_block(); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 4096); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.current_fees.account_create_fee, 1); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END()