Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable subjective account decay time #90

3 changes: 3 additions & 0 deletions docs/01_nodeos/03_plugins/producer_plugin/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ Config Options for eosio::producer_plugin:
transactions in any block before
returning to normal transaction
processing.
--subjective-account-decay-time-minutes (=1440)
Sets the time to return full subjective
cpu for accounts
--incoming-defer-ratio arg (=1) ratio between incoming transactions and
deferred transactions when both are
queued for execution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class subjective_billing {
uint64_t pending_cpu_us; // tracked cpu us for transactions that may still succeed in a block
decaying_accumulator expired_accumulator; // accumulator used to account for transactions that have expired

bool empty(uint32_t time_ordinal) {
bool empty(uint32_t time_ordinal, uint32_t expired_accumulator_average_window) {
return pending_cpu_us == 0 && expired_accumulator.value_at(time_ordinal, expired_accumulator_average_window) == 0;
}
};
Expand All @@ -61,6 +61,7 @@ class subjective_billing {
account_subjective_bill_cache _account_subjective_bill_cache;
block_subjective_bill_cache _block_subjective_bill_cache;
std::set<chain::account_name> _disabled_accounts;
uint32_t _expired_accumulator_average_window = config::account_cpu_usage_average_window_ms / subjective_time_interval_ms;

private:
uint32_t time_ordinal_for( const fc::time_point& t ) const {
Expand All @@ -75,15 +76,15 @@ class subjective_billing {
aitr->second.pending_cpu_us -= entry.subjective_cpu_bill;
EOS_ASSERT( aitr->second.pending_cpu_us >= 0, chain::tx_resource_exhaustion,
"Logic error in subjective account billing ${a}", ("a", entry.account) );
if( aitr->second.empty(time_ordinal) ) _account_subjective_bill_cache.erase( aitr );
if( aitr->second.empty(time_ordinal, _expired_accumulator_average_window) ) _account_subjective_bill_cache.erase( aitr );
}
}

void transition_to_expired( const trx_cache_entry& entry, uint32_t time_ordinal ) {
auto aitr = _account_subjective_bill_cache.find( entry.account );
if( aitr != _account_subjective_bill_cache.end() ) {
aitr->second.pending_cpu_us -= entry.subjective_cpu_bill;
aitr->second.expired_accumulator.add(entry.subjective_cpu_bill, time_ordinal, expired_accumulator_average_window);
aitr->second.expired_accumulator.add(entry.subjective_cpu_bill, time_ordinal, _expired_accumulator_average_window);
}
}

Expand All @@ -100,7 +101,6 @@ class subjective_billing {

public: // public for tests
static constexpr uint32_t subjective_time_interval_ms = 5'000;
static constexpr uint32_t expired_accumulator_average_window = config::account_cpu_usage_average_window_ms / subjective_time_interval_ms;

void remove_subjective_billing( const transaction_id_type& trx_id, uint32_t time_ordinal ) {
auto& idx = _trx_cache_index.get<by_id>();
Expand Down Expand Up @@ -140,7 +140,7 @@ class subjective_billing {
if( !_disabled && !_disabled_accounts.count( first_auth ) ) {
uint32_t bill = std::max<int64_t>( 0, elapsed.count() );
const auto time_ordinal = time_ordinal_for(now);
_account_subjective_bill_cache[first_auth].expired_accumulator.add(bill, time_ordinal, expired_accumulator_average_window);
_account_subjective_bill_cache[first_auth].expired_accumulator.add(bill, time_ordinal, _expired_accumulator_average_window);
}
}

Expand All @@ -160,7 +160,7 @@ class subjective_billing {

if (sub_bill_info) {
EOS_ASSERT(sub_bill_info->pending_cpu_us >= in_block_pending_cpu_us, chain::tx_resource_exhaustion, "Logic error subjective billing ${a}", ("a", first_auth) );
uint32_t sub_bill = sub_bill_info->pending_cpu_us - in_block_pending_cpu_us + sub_bill_info->expired_accumulator.value_at(time_ordinal, expired_accumulator_average_window );
uint32_t sub_bill = sub_bill_info->pending_cpu_us - in_block_pending_cpu_us + sub_bill_info->expired_accumulator.value_at(time_ordinal, _expired_accumulator_average_window );
return sub_bill;
} else {
return 0;
Expand Down Expand Up @@ -204,6 +204,15 @@ class subjective_billing {
}
return !exhausted;
}

uint32_t get_expired_accumulator_average_window() const {
return _expired_accumulator_average_window;
}

void set_expired_accumulator_average_window( fc::microseconds subjective_account_decay_time ) {
_expired_accumulator_average_window =
subjective_account_decay_time.count() / 1000 / subjective_time_interval_ms;
}
};

} //eosio
7 changes: 7 additions & 0 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,8 @@ void producer_plugin::set_program_options(
"Maximum wall-clock time, in milliseconds, spent retiring scheduled transactions in any block before returning to normal transaction processing.")
("subjective-cpu-leeway-us", boost::program_options::value<int32_t>()->default_value( config::default_subjective_cpu_leeway_us ),
"Time in microseconds allowed for a transaction that starts with insufficient CPU quota to complete and cover its CPU usage.")
("subjective-account-decay-time-minutes", bpo::value<uint32_t>()->default_value( config::account_cpu_usage_average_window_ms / 1000 / 60 ),
"Sets the time to return full subjective cpu for accounts")
("incoming-defer-ratio", bpo::value<double>()->default_value(1.0),
"ratio between incoming transactions and deferred transactions when both are queued for execution")
("incoming-transaction-queue-size-mb", bpo::value<uint16_t>()->default_value( 1024 ),
Expand Down Expand Up @@ -915,6 +917,11 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_
chain.set_subjective_cpu_leeway( fc::microseconds( options.at( "subjective-cpu-leeway-us" ).as<int32_t>() ) );
}

fc::microseconds subjective_account_decay_time = fc::minutes(options.at( "subjective-account-decay-time-minutes" ).as<uint32_t>());
EOS_ASSERT( subjective_account_decay_time.count() > 0, plugin_config_exception,
"subjective-account-decay-time-minutes ${dt} must be greater than 0", ("dt", subjective_account_decay_time.to_seconds() / 60));
my->_subjective_billing.set_expired_accumulator_average_window( subjective_account_decay_time );

my->_max_transaction_time_ms = options.at("max-transaction-time").as<int32_t>();

my->_max_irreversible_block_age_us = fc::seconds(options.at("max-irreversible-block-age").as<int32_t>());
Expand Down
7 changes: 4 additions & 3 deletions plugins/producer_plugin/test/test_subjective_billing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ BOOST_AUTO_TEST_CASE( subjective_bill_test ) {
account_name c = "c"_n;

const auto now = time_point::now();
const auto halftime = now + fc::milliseconds(subjective_billing::expired_accumulator_average_window * subjective_billing::subjective_time_interval_ms / 2);
const auto endtime = now + fc::milliseconds(subjective_billing::expired_accumulator_average_window * subjective_billing::subjective_time_interval_ms);

subjective_billing timing_sub_bill;
const auto halftime = now + fc::milliseconds(timing_sub_bill.get_expired_accumulator_average_window() * subjective_billing::subjective_time_interval_ms / 2);
const auto endtime = now + fc::milliseconds(timing_sub_bill.get_expired_accumulator_average_window() * subjective_billing::subjective_time_interval_ms);


{ // Failed transactions remain until expired in subjective billing.
Expand Down Expand Up @@ -129,7 +131,6 @@ BOOST_AUTO_TEST_CASE( subjective_bill_test ) {

{ // expired handling logic, full billing until expiration then failed/decay logic
subjective_billing sub_bill;
constexpr uint32_t window_size = subjective_billing::expired_accumulator_average_window;

sub_bill.subjective_bill( id1, now, a, fc::microseconds( 1024 ), false );
sub_bill.subjective_bill( id2, now + fc::microseconds(1), a, fc::microseconds( 1024 ), false );
Expand Down