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

[3.2] Enhancement: Add unique error message for subjective billing in the transaction trace logs #719

Merged
merged 3 commits into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions libraries/chain/include/eosio/chain/transaction_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ namespace eosio { namespace chain {
void schedule_transaction();
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );

void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const;
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit )const;
void validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const;
void validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;
void validate_account_cpu_usage_estimate( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const;

void disallow_transaction_extensions( const char* error_msg )const;

Expand Down
52 changes: 35 additions & 17 deletions libraries/chain/transaction_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ namespace eosio { namespace chain {
initial_objective_duration_limit = objective_duration_limit;

if( explicit_billed_cpu_time )
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false ); // Fail early if the amount to be billed is too high
validate_cpu_usage_to_bill( billed_cpu_time_us, std::numeric_limits<int64_t>::max(), false, subjective_cpu_bill_us); // Fail early if the amount to be billed is too high

// Record accounts to be billed for network and CPU usage
if( control.is_builtin_activated(builtin_protocol_feature_t::only_bill_first_authorizer) ) {
Expand Down Expand Up @@ -204,7 +204,7 @@ namespace eosio { namespace chain {
if( validate_account_cpu_limit > 0 )
validate_account_cpu_limit -= EOS_PERCENT( validate_account_cpu_limit, 10 * config::percent_1 );
if( validate_account_cpu_limit < 0 ) validate_account_cpu_limit = 0;
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit );
validate_account_cpu_usage_estimate( billed_cpu_time_us, validate_account_cpu_limit, subjective_cpu_bill_us );
}

eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes) so check_net_usage can be efficient
Expand Down Expand Up @@ -370,7 +370,7 @@ namespace eosio { namespace chain {

update_billed_cpu_time( now );

validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true );
validate_cpu_usage_to_bill( billed_cpu_time_us, account_cpu_limit, true, subjective_cpu_bill_us );

rl.add_transaction_usage( bill_to_accounts, static_cast<uint64_t>(billed_cpu_time_us), net_usage,
block_timestamp_type(control.pending_block_time()).slot ); // Should never fail
Expand Down Expand Up @@ -462,7 +462,7 @@ namespace eosio { namespace chain {
transaction_timer.start(_deadline);
}

void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum )const {
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, int64_t account_cpu_limit, bool check_minimum, int64_t subjective_billed_us )const {
if (!control.skip_trx_checks()) {
if( check_minimum ) {
const auto& cfg = control.get_global_properties().configuration;
Expand All @@ -472,11 +472,11 @@ namespace eosio { namespace chain {
);
}

validate_account_cpu_usage( billed_us, account_cpu_limit );
validate_account_cpu_usage( billed_us, account_cpu_limit, subjective_billed_us );
}
}

void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit )const {
void transaction_context::validate_account_cpu_usage( int64_t billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
if( (billed_us > 0) && !control.skip_trx_checks() ) {
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());

Expand All @@ -496,17 +496,26 @@ namespace eosio { namespace chain {
} else {
heifner marked this conversation as resolved.
Show resolved Hide resolved
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
EOS_ASSERT( billed_us <= cpu_limit,
tx_cpu_usage_exceeded,
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
("billed", billed_us)( "billable", cpu_limit )
);
if( subjective_billed_us > 0 ) {
EOS_ASSERT( billed_us <= cpu_limit,
tx_cpu_usage_exceeded,
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us) with a subjective cpu of (${subjective} us)",
("billed", billed_us)( "billable", cpu_limit )( "subjective", subjective_billed_us )
);
}
else {
EOS_ASSERT( billed_us <= cpu_limit,
tx_cpu_usage_exceeded,
"billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
("billed", billed_us)( "billable", cpu_limit )
heifner marked this conversation as resolved.
Show resolved Hide resolved
);
}
}
}
}
}

heifner marked this conversation as resolved.
Show resolved Hide resolved
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit )const {
void transaction_context::validate_account_cpu_usage_estimate( int64_t prev_billed_us, int64_t account_cpu_limit, int64_t subjective_billed_us )const {
// prev_billed_us can be 0, but so can account_cpu_limit
if( (prev_billed_us >= 0) && !control.skip_trx_checks() ) {
const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
Expand All @@ -527,11 +536,20 @@ namespace eosio { namespace chain {
} else {
// exceeds trx.max_cpu_usage_ms or cfg.max_transaction_cpu_usage if objective_duration_limit is greater
const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
EOS_ASSERT( prev_billed_us < cpu_limit,
tx_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
("billed", prev_billed_us)( "billable", cpu_limit )
);
if( subjective_billed_us > 0 ) {
EOS_ASSERT( prev_billed_us < cpu_limit,
tx_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us) with a subjective cpu of (${subjective} us)",
("billed", prev_billed_us)( "billable", cpu_limit )( "subjective", subjective_billed_us )
);
}
else {
EOS_ASSERT( prev_billed_us < cpu_limit,
tx_cpu_usage_exceeded,
"estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
("billed", prev_billed_us)( "billable", cpu_limit )
);
}
}
}
}
Expand Down