未验证 提交 4779ffb7 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #2734 from EOSIO/slim-resource-limits-fix2

Better CPU billing and configurable leeway on eager checks of CPU and network usage during transaction execution
......@@ -88,6 +88,7 @@
{"name":"target_block_net_usage_pct", "type": "uint32"},
{"name":"max_transaction_net_usage", "type":"uint32"},
{"name":"base_per_transaction_net_usage", "type":"uint32"},
{"name":"net_usage_leeway", "type":"uint32"},
{"name":"context_free_discount_net_usage_num", "type":"uint32"},
{"name":"context_free_discount_net_usage_den", "type":"uint32"},
{"name":"max_block_cpu_usage", "type": "uint64"},
......@@ -97,6 +98,7 @@
{"name":"base_per_action_cpu_usage", "type":"uint32"},
{"name":"base_setcode_cpu_usage", "type":"uint32"},
{"name":"per_signature_cpu_usage", "type":"uint32"},
{"name":"cpu_usage_leeway", "type":"uint32"},
{"name":"context_free_discount_cpu_usage_num", "type":"uint32"},
{"name":"context_free_discount_cpu_usage_den", "type":"uint32"},
{"name":"max_transaction_lifetime", "type":"uint32"},
......
......@@ -10,6 +10,7 @@ namespace eosio {
uint32_t target_block_net_usage_pct;
uint32_t max_transaction_net_usage;
uint32_t base_per_transaction_net_usage;
uint32_t net_usage_leeway;
uint32_t context_free_discount_net_usage_num;
uint32_t context_free_discount_net_usage_den;
......@@ -20,6 +21,7 @@ namespace eosio {
uint32_t base_per_action_cpu_usage;
uint32_t base_setcode_cpu_usage;
uint32_t per_signature_cpu_usage;
uint32_t cpu_usage_leeway;
uint32_t context_free_discount_cpu_usage_num;
uint32_t context_free_discount_cpu_usage_den;
......@@ -33,12 +35,12 @@ namespace eosio {
EOSLIB_SERIALIZE( blockchain_parameters,
(max_block_net_usage)(target_block_net_usage_pct)
(max_transaction_net_usage)(base_per_transaction_net_usage)
(max_transaction_net_usage)(base_per_transaction_net_usage)(net_usage_leeway)
(context_free_discount_net_usage_num)(context_free_discount_net_usage_den)
(max_block_cpu_usage)(target_block_cpu_usage_pct)
(max_transaction_cpu_usage)(base_per_transaction_cpu_usage)
(base_per_action_cpu_usage)(base_setcode_cpu_usage)(per_signature_cpu_usage)
(base_per_action_cpu_usage)(base_setcode_cpu_usage)(per_signature_cpu_usage)(cpu_usage_leeway)
(context_free_discount_cpu_usage_num)(context_free_discount_cpu_usage_den)
(max_transaction_lifetime)(deferred_trx_expiration_window)(max_transaction_delay)
......
......@@ -37,8 +37,13 @@ action_trace apply_context::exec_one()
auto start = fc::time_point::now();
cpu_usage = 0;
cpu_usage_limit = trx_context.get_action_cpu_usage_limit( context_free );
checktime( control.get_global_properties().configuration.base_per_action_cpu_usage );
const auto& cfg = control.get_global_properties().configuration;
checktime( cfg.base_per_action_cpu_usage );
try {
if( act.account == config::system_account_name && act.name == N(setcode) && receiver == config::system_account_name ) {
checktime( cfg.base_setcode_cpu_usage );
}
const auto &a = control.get_account(receiver);
privileged = a.privileged;
auto native = control.find_apply_handler(receiver, act.account, act.name);
......@@ -46,7 +51,7 @@ action_trace apply_context::exec_one()
(*native)(*this);
}
if (a.code.size() > 0 && !(act.name == N(setcode) && act.account == config::system_account_name)) {
if( a.code.size() > 0 && !(act.account == config::system_account_name && act.name == N(setcode)) ) {
try {
control.get_wasm_interface().apply(a.code_version, a.code, *this);
} catch ( const wasm_exit& ){}
......@@ -73,8 +78,7 @@ action_trace apply_context::exec_one()
t.total_cpu_usage = cpu_usage;
t.console = _pending_console_output.str();
executed.emplace_back( move(r) );
total_cpu_usage += cpu_usage;
trx_context.executed.emplace_back( move(r) );
print_debug(receiver, t);
......@@ -100,22 +104,13 @@ void apply_context::exec()
}
for( const auto& inline_action : _cfa_inline_actions ) {
apply_context ncontext( control, trx_context, inline_action, recurse_depth + 1 );
ncontext.context_free = true;
ncontext.exec();
fc::move_append( executed, move(ncontext.executed) );
total_cpu_usage += ncontext.trace.total_cpu_usage;
trace.total_cpu_usage += ncontext.trace.total_cpu_usage;
trace.inline_traces.emplace_back(ncontext.trace);
trace.inline_traces.emplace_back( trx_context.dispatch_action( inline_action, inline_action.account, true, recurse_depth + 1 ) );
trace.total_cpu_usage += trace.inline_traces.back().total_cpu_usage;
}
for( const auto& inline_action : _inline_actions ) {
apply_context ncontext( control, trx_context, inline_action, recurse_depth + 1 );
ncontext.exec();
fc::move_append( executed, move(ncontext.executed) );
total_cpu_usage += ncontext.total_cpu_usage;
trace.total_cpu_usage += ncontext.trace.total_cpu_usage;
trace.inline_traces.emplace_back(ncontext.trace);
trace.inline_traces.emplace_back( trx_context.dispatch_action( inline_action, inline_action.account, false, recurse_depth + 1 ) );
trace.total_cpu_usage += trace.inline_traces.back().total_cpu_usage;
}
} /// exec()
......@@ -355,7 +350,7 @@ void apply_context::reset_console() {
void apply_context::checktime(uint32_t instruction_count) {
cpu_usage += instruction_count;
EOS_ASSERT( BOOST_LIKELY(cpu_usage <= cpu_usage_limit), tx_cpu_usage_exceeded, "action cpu usage exceeded" );
EOS_ASSERT( BOOST_LIKELY(cpu_usage <= cpu_usage_limit), action_cpu_usage_exceeded, "action cpu usage exceeded" );
trx_context.check_time();
}
......
......@@ -439,13 +439,13 @@ struct controller_impl {
transaction_context trx_context( self, dtrx, gto.trx_id );
transaction_trace_ptr trace = trx_context.trace;
flat_set<account_name> bill_to_accounts;
uint64_t max_cpu;
uint64_t max_cpu = 0;
bool abort_on_error = false;
try {
trx_context.init_for_deferred_trx( deadline, gto.published );
bill_to_accounts = trx_context.bill_to_accounts;
max_cpu = trx_context.max_cpu;
max_cpu = trx_context.initial_max_billable_cpu;
trx_context.exec(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
trace->elapsed = fc::time_point::now() - start;
......@@ -574,7 +574,8 @@ struct controller_impl {
} else {
trx_context.init_for_input_trx( deadline,
trx->packed_trx.get_unprunable_size(),
trx->packed_trx.get_prunable_size() );
trx->packed_trx.get_prunable_size(),
trx->trx.signatures.size() );
}
fc::microseconds required_delay(0);
......
......@@ -606,11 +606,9 @@ class apply_context {
generic_index<index_double_object> idx_double;
generic_index<index_long_double_object> idx_long_double;
vector<action_receipt> executed;
action_trace trace;
uint64_t cpu_usage = 0;
uint64_t total_cpu_usage = 0;
uint64_t cpu_usage_limit = 0;
private:
......
......@@ -21,6 +21,7 @@ struct chain_config {
uint32_t target_block_net_usage_pct; ///< the target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion handling
uint32_t max_transaction_net_usage; ///< the maximum objectively measured net usage that the chain will allow regardless of account limits
uint32_t base_per_transaction_net_usage; ///< the base amount of net usage billed for a transaction to cover incidentals
uint32_t net_usage_leeway;
uint32_t context_free_discount_net_usage_num; ///< the numerator for the discount on net usage of context-free data
uint32_t context_free_discount_net_usage_den; ///< the denominator for the discount on net usage of context-free data
......@@ -31,6 +32,7 @@ struct chain_config {
uint32_t base_per_action_cpu_usage; ///< the base amount of cpu usage billed for an action to cover incidentals
uint32_t base_setcode_cpu_usage; ///< the base amount of cpu usage billed for a setcode action to cover compilation/etc
uint32_t per_signature_cpu_usage; ///< the cpu usage billed for every signature on a transaction
uint32_t cpu_usage_leeway;
uint32_t context_free_discount_cpu_usage_num; ///< the numerator for the discount on cpu usage of context-free actions
uint32_t context_free_discount_cpu_usage_den; ///< the denominator for the discount on cpu usage of context-free actions
......@@ -48,6 +50,7 @@ struct chain_config {
<< "Target Block Net Usage Percent: " << ((double)c.target_block_net_usage_pct / (double)config::percent_1) << "%, "
<< "Max Transaction Net Usage: " << c.max_transaction_net_usage << ", "
<< "Base Per-Transaction Net Usage: " << c.base_per_transaction_net_usage << ", "
<< "Net Usage Leeway: " << c.net_usage_leeway << ", "
<< "Context-Free Data Net Usage Discount: " << (double)c.context_free_discount_net_usage_num * 100.0 / (double)c.context_free_discount_net_usage_den << "% , "
<< "Max Block CPU Usage: " << c.max_block_cpu_usage << ", "
......@@ -57,6 +60,7 @@ struct chain_config {
<< "Base Per-Action CPU Usage: " << c.base_per_action_cpu_usage << ", "
<< "Base Setcode CPU Usage: " << c.base_setcode_cpu_usage << ", "
<< "Per-Signature CPU Usage: " << c.per_signature_cpu_usage << ", "
<< "CPU Usage Leeway: " << c.cpu_usage_leeway << ", "
<< "Context-Free Action CPU Usage Discount: " << (double)c.context_free_discount_cpu_usage_num * 100.0 / (double)c.context_free_discount_cpu_usage_den << "% , "
<< "Max Transaction Lifetime: " << c.max_transaction_lifetime << ", "
......@@ -76,12 +80,12 @@ inline bool operator!=(const chain_config& a, const chain_config& b) { return !(
FC_REFLECT(eosio::chain::chain_config,
(max_block_net_usage)(target_block_net_usage_pct)
(max_transaction_net_usage)(base_per_transaction_net_usage)
(max_transaction_net_usage)(base_per_transaction_net_usage)(net_usage_leeway)
(context_free_discount_net_usage_num)(context_free_discount_net_usage_den)
(max_block_cpu_usage)(target_block_cpu_usage_pct)
(max_transaction_cpu_usage)(base_per_transaction_cpu_usage)
(base_per_action_cpu_usage)(base_setcode_cpu_usage)(per_signature_cpu_usage)
(base_per_action_cpu_usage)(base_setcode_cpu_usage)(per_signature_cpu_usage)(cpu_usage_leeway)
(context_free_discount_cpu_usage_num)(context_free_discount_cpu_usage_den)
(max_transaction_lifetime)(deferred_trx_expiration_window)(max_transaction_delay)
......
......@@ -58,6 +58,7 @@ const static uint32_t default_max_block_net_usage = 1024 * 102
const static uint32_t default_target_block_net_usage_pct = 10 * percent_1; /// we target 1000 TPS
const static uint32_t default_max_transaction_net_usage = default_max_block_net_usage / 10;
const static uint32_t default_base_per_transaction_net_usage = 12; // 12 bytes (11 bytes for worst case of transaction_receipt_header + 1 byte for static_variant tag)
const static uint32_t default_net_usage_leeway = 500; // TODO: is this reasonable?
const static uint32_t default_context_free_discount_net_usage_num = 20; // TODO: is this reasonable?
const static uint32_t default_context_free_discount_net_usage_den = 100;
const static uint32_t transaction_id_net_usage = 32; // 32 bytes for the size of a transaction id
......@@ -69,6 +70,7 @@ const static uint32_t default_base_per_transaction_cpu_usage = 512;
const static uint32_t default_base_per_action_cpu_usage = 1024;
const static uint32_t default_base_setcode_cpu_usage = 2 * 1024 * 1024; /// overbilling cpu usage for setcode to cover incidental
const static uint32_t default_per_signature_cpu_usage = 100 * 1024; // TODO: is this reasonable?
const static uint32_t default_cpu_usage_leeway = 2048; // TODO: is this reasonable?
const static uint32_t default_context_free_discount_cpu_usage_num = 20;
const static uint32_t default_context_free_discount_cpu_usage_den = 100;
......
......@@ -217,7 +217,8 @@ namespace eosio { namespace chain {
3080005, "transaction CPU usage is too much for the remaining allowable usage of the current block" )
FC_DECLARE_DERIVED_EXCEPTION( tx_deadline_exceeded, resource_exhausted_exception,
3080006, "transaction took too long" )
FC_DECLARE_DERIVED_EXCEPTION( action_cpu_usage_exceeded, resource_exhausted_exception,
3080007, "action took too long" )
FC_DECLARE_DERIVED_EXCEPTION( misc_exception, chain_exception,
3090000, "Miscellaneous exception" )
......
......@@ -21,6 +21,7 @@ struct genesis_state {
.target_block_net_usage_pct = config::default_target_block_net_usage_pct,
.max_transaction_net_usage = config::default_max_transaction_net_usage,
.base_per_transaction_net_usage = config::default_base_per_transaction_net_usage,
.net_usage_leeway = config::default_net_usage_leeway,
.context_free_discount_net_usage_num = config::default_context_free_discount_net_usage_num,
.context_free_discount_net_usage_den = config::default_context_free_discount_net_usage_den,
......@@ -31,6 +32,7 @@ struct genesis_state {
.base_per_action_cpu_usage = config::default_base_per_action_cpu_usage,
.base_setcode_cpu_usage = config::default_base_setcode_cpu_usage,
.per_signature_cpu_usage = config::default_per_signature_cpu_usage,
.cpu_usage_leeway = config::default_cpu_usage_leeway,
.context_free_discount_cpu_usage_num = config::default_context_free_discount_cpu_usage_num,
.context_free_discount_cpu_usage_den = config::default_context_free_discount_cpu_usage_den,
......
......@@ -4,7 +4,6 @@
namespace eosio { namespace chain {
class transaction_context {
private:
void init( uint64_t initial_net_usage, uint64_t initial_cpu_usage );
......@@ -21,7 +20,8 @@ namespace eosio { namespace chain {
void init_for_input_trx( fc::time_point deadline,
uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size );
uint64_t packed_trx_prunable_size,
uint32_t num_signatures );
void init_for_deferred_trx( fc::time_point deadline,
fc::time_point published );
......@@ -44,9 +44,11 @@ namespace eosio { namespace chain {
private:
void dispatch_action( const action& a, account_name receiver, bool context_free = false );
inline void dispatch_action( const action& a, bool context_free = false ) {
dispatch_action(a, a.account, context_free);
friend class apply_context;
action_trace dispatch_action( const action& a, account_name receiver, bool context_free = false, uint32_t recurse_depth = 0 );
inline action_trace dispatch_action( const action& a, bool context_free = false ) {
return dispatch_action(a, a.account, context_free);
};
void schedule_transaction();
void record_transaction( const transaction_id_type& id, fc::time_point_sec expire );
......@@ -65,8 +67,17 @@ namespace eosio { namespace chain {
vector<action_receipt> executed;
flat_set<account_name> bill_to_accounts;
flat_set<account_name> validate_ram_usage;
uint64_t max_net = 0; /// the maximum number of network usage bytes the transaction can consume
uint64_t max_cpu = 0; /// the maximum number of CPU instructions the transaction may consume
/// the maximum number of network usage bytes the transaction can consume (ignoring what billable accounts can pay and ignoring the remaining usage available in the block)
uint64_t max_net = 0;
uint64_t eager_net_limit = 0; ///< net usage limit (in bytes) to check against eagerly
/// the maximum number of virtual CPU instructions the transaction may consume (ignoring what billable accounts can pay and ignoring the remaining usage available in the block)
uint64_t max_cpu = 0;
uint64_t eager_cpu_limit = 0; ///< cpu usage limit (in virtual CPU instructions) to check against eagerly
/// the maximum number of virtual CPU instructions of the transaction that can be safely billed to the billable accounts
uint64_t initial_max_billable_cpu = 0;
fc::microseconds delay;
bool is_input = false;
bool apply_context_free = true;
......
......@@ -155,10 +155,10 @@ void resource_limits_manager::verify_account_ram_usage( const account_name accou
get_account_limits( account, ram_bytes, net_weight, cpu_weight );
const auto& usage = _db.get<resource_usage_object,by_owner>( account );
if( ram_bytes >= 0 && usage.ram_usage > ram_bytes ) {
ram_usage_exceeded e(FC_LOG_MESSAGE(error, "account ${a} has insufficient ram bytes", ("a", account)));
e.append_log(FC_LOG_MESSAGE(error, "needs ${d} has ${m}", ("d",usage.ram_usage)("m",ram_bytes)));
throw e;
if( ram_bytes >= 0 ) {
EOS_ASSERT( usage.ram_usage <= ram_bytes, ram_usage_exceeded,
"account ${account} has insufficient ram bytes; needs ${available} has ${needs}",
("account", account)("available",usage.ram_usage)("needs",ram_bytes) );
}
}
......
......@@ -52,6 +52,25 @@ namespace eosio { namespace chain {
if( trx_specified_cpu_usage_limit > 0 )
max_cpu = std::min( max_cpu, trx_specified_cpu_usage_limit );
eager_net_limit = max_net;
eager_cpu_limit = max_cpu;
// Update usage values of accounts to reflect new time
auto& rl = control.get_mutable_resource_limits_manager();
rl.add_transaction_usage( bill_to_accounts, 0, 0, block_timestamp_type(control.pending_block_time()).slot );
uint64_t block_net_limit = rl.get_block_net_limit();
uint64_t block_cpu_limit = rl.get_block_cpu_limit();
if( block_net_limit < eager_net_limit ) {
eager_net_limit = block_net_limit;
net_limit_due_to_block = true;
}
if( block_cpu_limit < eager_cpu_limit ) {
eager_cpu_limit = block_cpu_limit;
cpu_limit_due_to_block = true;
}
// Initial billing for network usage
if( initial_net_usage > 0 )
add_net_usage( initial_net_usage );
......@@ -63,32 +82,43 @@ namespace eosio { namespace chain {
+ bill_to_accounts.size() * config::resource_processing_cpu_overhead_per_billed_account );
// Fails early if current CPU usage is already greater than the current limit (which may still go lower).
// Update usage values of accounts to reflect new time
auto& rl = control.get_mutable_resource_limits_manager();
rl.add_transaction_usage( bill_to_accounts, 0, 0, block_timestamp_type(control.pending_block_time()).slot );
eager_net_limit = max_net;
eager_cpu_limit = max_cpu;
net_limit_due_to_block = false;
cpu_limit_due_to_block = false;
// Lower limits to what the billed accounts can afford to pay
for( const auto& a : bill_to_accounts ) {
auto net_limit = rl.get_account_net_limit(a);
if( net_limit >= 0 )
max_net = std::min( max_net, static_cast<uint64_t>(net_limit) ); // reduce max_net to the amount the account is able to pay
eager_net_limit = std::min( eager_net_limit, static_cast<uint64_t>(net_limit) ); // reduce max_net to the amount the account is able to pay
auto cpu_limit = rl.get_account_cpu_limit(a);
if( cpu_limit >= 0 )
max_cpu = std::min( max_cpu, static_cast<uint64_t>(cpu_limit) ); // reduce max_cpu to the amount the account is able to pay
eager_cpu_limit = std::min( eager_cpu_limit, static_cast<uint64_t>(cpu_limit) ); // reduce max_cpu to the amount the account is able to pay
}
if( rl.get_block_net_limit() < max_net ) {
max_net = rl.get_block_net_limit();
initial_max_billable_cpu = eager_cpu_limit; // Possibly used for hard failure purposes
eager_net_limit += cfg.net_usage_leeway;
eager_net_limit = std::min(eager_net_limit, max_net);
eager_cpu_limit += cfg.cpu_usage_leeway;
eager_cpu_limit = std::min(eager_cpu_limit, max_cpu);
if( block_net_limit < eager_net_limit ) {
eager_net_limit = block_net_limit;
net_limit_due_to_block = true;
}
if( rl.get_block_cpu_limit() < max_cpu ) {
max_cpu = rl.get_block_cpu_limit();
if( block_cpu_limit < eager_cpu_limit ) {
eager_cpu_limit = block_cpu_limit;
cpu_limit_due_to_block = true;
}
// Round down network and CPU usage limits so that comparison to actual usage is more efficient
max_net = (max_net/8)*8; // Round down to nearest multiple of word size (8 bytes)
max_cpu = (max_cpu/1024)*1024; // Round down to nearest multiple of 1024
eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes)
eager_cpu_limit = (eager_cpu_limit/1024)*1024; // Round down to nearest multiple of 1024
if( initial_net_usage > 0 )
check_net_usage(); // Fail early if current net usage is already greater than the calculated limit
check_cpu_usage(); // Fail early if current CPU usage is already greater than the calculated limit
......@@ -105,7 +135,8 @@ namespace eosio { namespace chain {
void transaction_context::init_for_input_trx( fc::time_point d,
uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size )
uint64_t packed_trx_prunable_size,
uint32_t num_signatures )
{
const auto& cfg = control.get_global_properties().configuration;
......@@ -121,6 +152,8 @@ namespace eosio { namespace chain {
uint64_t initial_net_usage = static_cast<uint64_t>(cfg.base_per_transaction_net_usage)
+ packed_trx_unprunable_size + discounted_size_for_pruned_data;
uint64_t initial_cpu_usage = num_signatures * cfg.per_signature_cpu_usage;
if( trx.delay_sec.value > 0 ) {
// If delayed, also charge ahead of time for the additional net usage needed to retire the delayed transaction
// whether that be by successfully executing, soft failure, hard failure, or expiration.
......@@ -131,7 +164,7 @@ namespace eosio { namespace chain {
published = control.pending_block_time();
deadline = d;
is_input = true;
init( initial_net_usage, 0 );
init( initial_net_usage, initial_cpu_usage );
}
void transaction_context::init_for_deferred_trx( fc::time_point d,
......@@ -158,13 +191,15 @@ namespace eosio { namespace chain {
if( apply_context_free ) {
for( const auto& act : trx.context_free_actions ) {
dispatch_action( act, true );
trace->action_traces.emplace_back();
trace->action_traces.back() = dispatch_action( act, true );
}
}
if( delay == fc::microseconds() ) {
for( const auto& act : trx.actions ) {
dispatch_action( act );
trace->action_traces.emplace_back();
trace->action_traces.back() = dispatch_action( act );
}
} else {
schedule_transaction();
......@@ -177,11 +212,30 @@ namespace eosio { namespace chain {
rl.verify_account_ram_usage( a );
}
eager_net_limit = max_net;
eager_cpu_limit = max_cpu;
net_limit_due_to_block = false;
cpu_limit_due_to_block = false;
// Lower limits to what the billed accounts can afford to pay
for( const auto& a : bill_to_accounts ) {
auto net_limit = rl.get_account_net_limit(a);
if( net_limit >= 0 )
eager_net_limit = std::min( eager_net_limit, static_cast<uint64_t>(net_limit) ); // reduce max_net to the amount the account is able to pay
auto cpu_limit = rl.get_account_cpu_limit(a);
if( cpu_limit >= 0 )
eager_cpu_limit = std::min( eager_cpu_limit, static_cast<uint64_t>(cpu_limit) ); // reduce max_cpu to the amount the account is able to pay
}
net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)
cpu_usage = ((cpu_usage + 1023)/1024)*1024; // Round up to nearest multiple of 1024
control.get_mutable_resource_limits_manager()
.add_transaction_usage( bill_to_accounts, cpu_usage, net_usage,
block_timestamp_type(control.pending_block_time()).slot );
check_net_usage();
check_cpu_usage();
rl.add_transaction_usage( bill_to_accounts, cpu_usage, net_usage,
block_timestamp_type(control.pending_block_time()).slot ); // Should never fail
}
void transaction_context::squash() {
......@@ -221,7 +275,7 @@ namespace eosio { namespace chain {
}
void transaction_context::check_net_usage()const {
if( BOOST_UNLIKELY(net_usage > max_net) ) {
if( BOOST_UNLIKELY(net_usage > eager_net_limit) ) {
if( BOOST_UNLIKELY( net_limit_due_to_block ) ) {
EOS_THROW( tx_soft_net_usage_exceeded,
"not enough space left in block: ${actual_net_usage} > ${net_usage_limit}",
......@@ -235,7 +289,7 @@ namespace eosio { namespace chain {
}
void transaction_context::check_cpu_usage()const {
if( BOOST_UNLIKELY(cpu_usage > max_cpu) ) {
if( BOOST_UNLIKELY(cpu_usage > eager_cpu_limit) ) {
if( BOOST_UNLIKELY( cpu_limit_due_to_block ) ) {
EOS_THROW( tx_soft_cpu_usage_exceeded,
"not enough CPU usage allotment left in block: ${actual_cpu_usage} > ${cpu_usage_limit}",
......@@ -260,23 +314,19 @@ namespace eosio { namespace chain {
}
}
void transaction_context::dispatch_action( const action& a, account_name receiver, bool context_free ) {
apply_context acontext( control, *this, a );
action_trace transaction_context::dispatch_action( const action& a, account_name receiver, bool context_free, uint32_t recurse_depth ) {
apply_context acontext( control, *this, a, recurse_depth );
acontext.context_free = context_free;
acontext.receiver = receiver;
try {
acontext.exec();
} catch( const tx_cpu_usage_exceeded& e ) {
} catch( const action_cpu_usage_exceeded& e ) {
add_action_cpu_usage( acontext.cpu_usage, context_free ); // Will update cpu_usage to latest value and throw appropriate exception
FC_ASSERT(false, "should not have reached here" );
} catch( ... ) {
throw;
}
fc::move_append(executed, move(acontext.executed) );
trace->action_traces.emplace_back( move(acontext.trace) );
return move(acontext.trace);
}
void transaction_context::schedule_transaction() {
......
......@@ -193,6 +193,7 @@ class privileged_api : public context_aware_api {
};
/*
class checktime_api : public context_aware_api {
public:
explicit checktime_api( apply_context& ctx )
......@@ -202,6 +203,7 @@ public:
context.checktime(instruction_count);
}
};
*/
class softfloat_api : public context_aware_api {
public:
......@@ -1621,7 +1623,7 @@ REGISTER_INTRINSICS(privileged_api,
(set_privileged, void(int64_t, int) )
);
REGISTER_INJECTED_INTRINSICS(checktime_api,
REGISTER_INJECTED_INTRINSICS(apply_context,
(checktime, void(int))
);
......
......@@ -94,7 +94,7 @@ namespace eosio { namespace testing {
transaction_trace_ptr push_action( const account_name& code, const action_name& acttype, const vector<permission_level>& auths, const variant_object& data, uint32_t expiration = DEFAULT_EXPIRATION_DELTA, uint32_t delay_sec = 0 );
action get_action( account_name code, action_name acttype, vector<permission_level> auths,
action get_action( account_name code, action_name acttype, vector<permission_level> auths,
const variant_object& data )const;
void set_transaction_headers(signed_transaction& trx,
......@@ -326,23 +326,11 @@ namespace eosio { namespace testing {
};
/**
* Utility predicate to check whether an FC_ASSERT message ends with a given string
* Utility predicate to check whether an fc::exception message is equivalent to a given string
*/
struct assert_message_ends_with {
assert_message_ends_with( string expected )
: expected( expected ) {}
bool operator()( const fc::exception& ex );
string expected;
};
/**
* Utility predicate to check whether an FC_ASSERT message contains a given string
*/
struct assert_message_contains {
assert_message_contains( string expected )
: expected( expected ) {}
struct fc_exception_message_is {
fc_exception_message_is( const string& msg )
: expected( msg ) {}
bool operator()( const fc::exception& ex );
......
......@@ -695,14 +695,13 @@ namespace eosio { namespace testing {
return tid;
}
bool assert_message_ends_with::operator()( const fc::exception& ex ) {
bool fc_exception_message_is::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
return boost::algorithm::ends_with( message, expected );
}
bool assert_message_contains::operator()( const fc::exception& ex ) {
auto message = ex.get_log().at( 0 ).get_message();
return boost::algorithm::contains( message, expected );
bool match = (message == expected);
if( !match ) {
BOOST_TEST_MESSAGE( "LOG: expected: " << expected << ", actual: " << message );
}
return match;
}
bool fc_exception_message_starts_with::operator()( const fc::exception& ex ) {
......@@ -770,7 +769,7 @@ namespace eosio { namespace testing {
return match;
}
} } /// eosio::test
} } /// eosio::testing
std::ostream& operator<<( std::ostream& osm, const fc::variant& v ) {
//fc::json::to_stream( osm, v );
......
......@@ -410,6 +410,7 @@ fc::variant regproducer_variant(const account_name& producer,
("target_block_net_usage_pct", config::default_target_block_net_usage_pct)
("max_transaction_net_usage", config::default_max_transaction_net_usage)
("base_per_transaction_net_usage", config::default_base_per_transaction_net_usage)
("net_usage_leeway", config::default_net_usage_leeway)
("context_free_discount_net_usage_num", config::default_context_free_discount_net_usage_num)
("context_free_discount_net_usage_den", config::default_context_free_discount_net_usage_den)
("max_block_cpu_usage", config::default_max_block_cpu_usage)
......@@ -419,6 +420,7 @@ fc::variant regproducer_variant(const account_name& producer,
("base_per_action_cpu_usage", config::default_base_per_action_cpu_usage)
("base_setcode_cpu_usage", config::default_base_setcode_cpu_usage)
("per_signature_cpu_usage", config::default_per_signature_cpu_usage)
("cpu_usage_leeway", config::default_cpu_usage_leeway)
("context_free_discount_cpu_usage_num", config::default_context_free_discount_cpu_usage_num)
("context_free_discount_cpu_usage_den", config::default_context_free_discount_cpu_usage_den)
("max_transaction_lifetime", config::default_max_trx_lifetime)
......
......@@ -291,11 +291,11 @@ try {
// Create duplicate name
BOOST_CHECK_EXCEPTION(chain.create_account("joe"), action_validate_exception,
assert_message_ends_with("Cannot create account named joe, as that name is already taken"));
fc_exception_message_is("Cannot create account named joe, as that name is already taken"));
// Creating account with name more than 12 chars
BOOST_CHECK_EXCEPTION(chain.create_account("aaaaaaaaaaaaa"), action_validate_exception,
assert_message_ends_with("account names can only be 12 chars long"));
fc_exception_message_is("account names can only be 12 chars long"));
// Creating account with eosio. prefix with privileged account
......@@ -303,7 +303,7 @@ try {
// Creating account with eosio. prefix with non-privileged account, should fail
BOOST_CHECK_EXCEPTION(chain.create_account("eosio.test2", "joe"), action_validate_exception,
assert_message_ends_with("only privileged accounts can have names that start with 'eosio.'"));
fc_exception_message_is("only privileged accounts can have names that start with 'eosio.'"));
} FC_LOG_AND_RETHROW() }
......
......@@ -62,7 +62,7 @@ class currency_tester : public TESTER {
produce_block();
return trace;
}
currency_tester()
:TESTER(),abi_ser(json::from_string(eosio_token_abi).as<abi_def>())
{
......@@ -205,7 +205,8 @@ BOOST_FIXTURE_TEST_CASE( test_overspend, currency_tester ) try {
("quantity", "101.0000 CUR")
("memo", "overspend! Alice");
BOOST_CHECK_EXCEPTION(push_action(N(alice), N(transfer), data), fc::exception, assert_message_contains("overdrawn balance"));
BOOST_CHECK_EXCEPTION( push_action(N(alice), N(transfer), data),
fc::assert_exception, eosio_assert_message_is("overdrawn balance") );
produce_block();
BOOST_REQUIRE_EQUAL(get_balance(N(alice)), asset::from_string( "100.0000 CUR" ));
......@@ -286,13 +287,13 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try {
// from empty string
{
BOOST_CHECK_EXCEPTION(symbol::from_string(""),
fc::assert_exception, assert_message_ends_with("creating symbol from empty string"));
fc::assert_exception, fc_assert_exception_message_is("creating symbol from empty string"));
}
// precision part missing
{
BOOST_CHECK_EXCEPTION(symbol::from_string("RND"),
fc::assert_exception, assert_message_ends_with("missing comma in symbol"));
fc::assert_exception, fc_assert_exception_message_is("missing comma in symbol"));
}
// 0 decimals part
......@@ -305,13 +306,13 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try {
// invalid - contains lower case characters, no validation
{
BOOST_CHECK_EXCEPTION(symbol malformed(SY(6,EoS)),
fc::assert_exception, assert_message_contains("invalid symbol"));
fc::assert_exception, fc_assert_exception_message_is("invalid symbol"));
}
// invalid - contains lower case characters, exception thrown
{
BOOST_CHECK_EXCEPTION(symbol(5,"EoS"),
fc::assert_exception, assert_message_ends_with("invalid character in symbol name"));
fc::assert_exception, fc_assert_exception_message_is("invalid character in symbol name"));
}
// Missing decimal point, should create asset with 0 decimals
......@@ -326,19 +327,19 @@ BOOST_FIXTURE_TEST_CASE(test_symbol, TESTER) try {
// Missing space
{
BOOST_CHECK_EXCEPTION(asset::from_string("10CUR"),
asset_type_exception, assert_message_ends_with("Asset's amount and symbol should be separated with space"));
asset_type_exception, fc_exception_message_is("Asset's amount and symbol should be separated with space"));
}
// Precision is not specified when decimal separator is introduced
{
BOOST_CHECK_EXCEPTION(asset::from_string("10. CUR"),
asset_type_exception, assert_message_ends_with("Missing decimal fraction after decimal point"));
asset_type_exception, fc_exception_message_is("Missing decimal fraction after decimal point"));
}
// Missing symbol
{
BOOST_CHECK_EXCEPTION(asset::from_string("10"),
asset_type_exception, assert_message_ends_with("Asset's amount and symbol should be separated with space"));
asset_type_exception, fc_exception_message_is("Asset's amount and symbol should be separated with space"));
}
// Multiple spaces
......@@ -534,7 +535,7 @@ BOOST_FIXTURE_TEST_CASE( test_deferred_failure, currency_tester ) try {
BOOST_FIXTURE_TEST_CASE( test_input_quantity, currency_tester ) try {
produce_blocks(2);
create_accounts( {N(alice), N(bob), N(carl)} );
// transfer to alice using right precision
......@@ -566,15 +567,13 @@ BOOST_FIXTURE_TEST_CASE( test_input_quantity, currency_tester ) try {
// transfer using higher precision fails
{
BOOST_REQUIRE_EXCEPTION(transfer(N(alice), N(carl), "5.34567 CUR"), assert_exception,
[](const assert_exception& e) -> bool {
return e.get_log().at(0).get_message() == "condition: assertion failed: asset symbol has higher precision than expected";
});
BOOST_REQUIRE_EXCEPTION( transfer(N(alice), N(carl), "5.34567 CUR"), fc::assert_exception,
eosio_assert_message_is("asset symbol has higher precision than expected") );
}
// transfer using different symbol name fails
{
BOOST_REQUIRE_THROW(transfer(N(alice), N(carl), "20.50 USD"), assert_exception);
BOOST_REQUIRE_THROW(transfer(N(alice), N(carl), "20.50 USD"), fc::assert_exception);
}
} FC_LOG_AND_RETHROW() /// test_currency
......
......@@ -156,6 +156,7 @@ public:
("target_block_net_usage_pct", 10 + n )
("max_transaction_net_usage", 1000000 + n )
("base_per_transaction_net_usage", 100 + n)
("net_usage_leeway", 500 + n )
("context_free_discount_net_usage_num", 1 + n )
("context_free_discount_net_usage_den", 100 + n )
("max_block_cpu_usage", 10000000 + n )
......@@ -165,6 +166,7 @@ public:
("base_per_action_cpu_usage", 100 + n)
("base_setcode_cpu_usage", 100 + n)
("per_signature_cpu_usage", 100 + n)
("cpu_usage_leeway", 2048 + n )
("context_free_discount_cpu_usage_num", 1 + n )
("context_free_discount_cpu_usage_den", 100 + n )
("max_transaction_lifetime", 3600 + n)
......
......@@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try {
("host", "player1")
("by", "player1")
("mvt", mvt)
), assert_exception, assert_message_contains("not your turn"));
), assert_exception, eosio_assert_message_starts_with("it's not your turn yet"));
mvt = mutable_variant_object()
("row", 1)
......@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try {
("host", "player1")
("by", "player2")
("mvt", mvt)
), assert_exception, assert_message_contains("not a valid movement"));
), assert_exception, eosio_assert_message_starts_with("not a valid movement"));
mvt = mutable_variant_object()
("row", 0)
......@@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try {
("host", "player1")
("by", "player2")
("mvt", mvt)
), assert_exception, assert_message_contains("the game has ended"));
), assert_exception, eosio_assert_message_starts_with("the game has ended"));
game current;
chain.get_table_entry(current, N(tic.tac.toe), N(player1), N(games), N(player2));
......@@ -181,13 +181,13 @@ BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try {
("host", "player1")
("by", "player2")
("mvt", mvt)
), assert_exception, assert_message_contains("game doesn't exists"));
), assert_exception, eosio_assert_message_starts_with("game doesn't exists"));
BOOST_CHECK_EXCEPTION(chain.push_action(N(tic.tac.toe), N(restart), N(player2), mutable_variant_object()
("challenger", "player2")
("host", "player1")
("by", "player2")
), assert_exception, assert_message_contains("game doesn't exists"));
), assert_exception, eosio_assert_message_starts_with("game doesn't exists"));
chain.push_action(N(tic.tac.toe), N(create), N(player2), mutable_variant_object()
("challenger", "player1")
......@@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE( tic_tac_toe_game ) try {
("host", "player2")
("by", "player2")
("mvt", mvt)
), assert_exception, assert_message_contains("not your turn"));
), assert_exception, eosio_assert_message_starts_with("it's not your turn yet"));
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
......@@ -515,7 +515,7 @@ BOOST_FIXTURE_TEST_CASE(misaligned_tests, tester ) try {
// test cpu usage
BOOST_FIXTURE_TEST_CASE(cpu_usage_tests, tester ) try {
#warning This test does not appear to be very robust.
create_accounts( {N(f_tests)} );
bool pass = false;
......@@ -539,8 +539,15 @@ BOOST_FIXTURE_TEST_CASE(cpu_usage_tests, tester ) try {
set_code(N(f_tests), code.c_str());
produce_blocks(10);
int limit = 190;
while (!pass && limit < 200) {
uint32_t start = config::default_per_signature_cpu_usage + config::default_base_per_transaction_cpu_usage;
start += 100 * (config::default_base_per_action_cpu_usage + config::determine_payers_cpu_overhead_per_authorization);
start += config::resource_processing_cpu_overhead_per_billed_account;
start /= 1024;
--start;
wdump((start));
uint32_t end = start + 5;
uint32_t limit = start;
for( limit = start; limit < end; ++limit ) {
signed_transaction trx;
for (int i = 0; i < 100; ++i) {
......@@ -559,21 +566,20 @@ BOOST_FIXTURE_TEST_CASE(cpu_usage_tests, tester ) try {
push_transaction(trx);
produce_blocks(1);
BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
pass = true;
break;
} catch (eosio::chain::tx_cpu_usage_exceeded &) {
produce_blocks(1);
}
BOOST_REQUIRE_EQUAL(true, validate());
}
// NOTE: limit is 197
BOOST_REQUIRE_EQUAL(true, limit > 190 && limit < 200);
wdump((limit));
BOOST_CHECK_EQUAL(true, start < limit && limit < end);
} FC_LOG_AND_RETHROW()
// test weighted cpu limit
BOOST_FIXTURE_TEST_CASE(weighted_cpu_limit_tests, tester ) try {
#warning This test does not appear to be very robust.
resource_limits_manager mgr = control->get_mutable_resource_limits_manager();
create_accounts( {N(f_tests)} );
create_accounts( {N(acc2)} );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册