未验证 提交 fd79fc31 编写于 作者: A arhag 提交者: GitHub

Merge branch 'slim' into issue-2928

......@@ -120,7 +120,7 @@ namespace eosiosystem {
auto itr = _rammarket.find(S(4,RAMEOS));
auto tmp = *itr;
auto eosout = tmp.convert( asset(bytes,S(0,RAM)), S(4,EOS) );
print( "eosout: ", eosout, "\n" );
print( "eosout: ", eosout, " ", tmp.base.balance, " ", tmp.quote.balance, "\n" );
buyram( payer, receiver, eosout );
}
......
......@@ -23,14 +23,16 @@ namespace eosiosystem {
if( itr == _rammarket.end() ) {
auto system_token_supply = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
itr = _rammarket.emplace( _self, [&]( auto& m ) {
m.supply.amount = 100000000000000ll;
m.supply.symbol = S(4,RAMEOS);
m.base.balance.amount = int64_t(_gstate.free_ram());
m.base.balance.symbol = S(0,RAM);
m.quote.balance.amount = system_token_supply / 1000;
m.quote.balance.symbol = S(4,EOS);
});
if( system_token_supply > 0 ) {
itr = _rammarket.emplace( _self, [&]( auto& m ) {
m.supply.amount = 100000000000000ll;
m.supply.symbol = S(4,RAMEOS);
m.base.balance.amount = int64_t(_gstate.free_ram());
m.base.balance.symbol = S(0,RAM);
m.quote.balance.amount = system_token_supply / 1000;
m.quote.balance.symbol = S(4,EOS);
});
}
} else {
//print( "ram market already created" );
}
......
......@@ -28,6 +28,8 @@ namespace eosiosystem {
void system_contract::onblock( block_timestamp timestamp, account_name producer ) {
using namespace eosio;
require_auth(N(eosio));
/** until activated stake crosses this threshold no new rewards are paid */
if( _gstate.total_activated_stake < 150'000'000'0000 )
return;
......@@ -42,7 +44,7 @@ namespace eosiosystem {
p.last_produced_block_time = timestamp;
});
}
/// only update block producers once every minute, block_timestamp is in half seconds
if( timestamp - _gstate.last_producer_schedule_update > 120 ) {
update_elected_producers( timestamp );
......@@ -53,7 +55,7 @@ namespace eosiosystem {
eosio::asset system_contract::payment_per_vote( const account_name& owner, double owners_votes, const eosio::asset& pervote_bucket ) {
eosio::asset payment(0, S(4,EOS));
const int64_t min_daily_amount = 100 * 10000;
if ( pervote_bucket.amount < min_daily_tokens ) {
if ( pervote_bucket.amount < min_daily_amount ) {
return payment;
}
......@@ -66,7 +68,7 @@ namespace eosiosystem {
if ( !(itr->total_votes > 0) ) {
break;
}
if ( !(itr->active()) && !(itr->owner != owner) ) {
if ( !itr->active() ) {
continue;
}
......@@ -99,6 +101,7 @@ namespace eosiosystem {
auto prod = _producers.find( owner );
eosio_assert( prod != _producers.end(), "account name is not in producer list" );
eosio_assert( prod->active(), "producer does not have an active key" );
if( prod->last_claim_time > 0 ) {
eosio_assert(current_time() >= prod->last_claim_time + useconds_per_day, "already claimed rewards within a day");
}
......
......@@ -78,8 +78,24 @@ namespace eosiosystem {
for ( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes; ++it ) {
if( !it->active() ) continue;
if ( it->time_became_active == 0 ) {
_producers.modify( *it, 0, [&](auto& p) {
p.time_became_active = block_time;
});
} else if ( block_time > 2 * 21 * 12 + it->time_became_active &&
block_time > it->last_produced_block_time + blocks_per_day ) {
_producers.modify( *it, 0, [&](auto& p) {
p.producer_key = public_key();
p.time_became_active = 0;
});
continue;
}
top_producers.emplace_back( std::pair<eosio::producer_key,uint16_t>({{it->owner, it->producer_key}, it->location}));
}
/// sort by producer name
......@@ -139,6 +155,7 @@ namespace eosiosystem {
auto voter = _voters.find(voter_name);
eosio_assert( voter != _voters.end(), "user must stake before they can vote" ); /// staking creates voter object
eosio_assert( !proxy || !voter->is_proxy, "account registered as a proxy is not allowed to use a proxy" );
/**
* The first time someone votes we calculate and set last_vote_weight, since they cannot unstake until
......@@ -229,11 +246,9 @@ namespace eosiosystem {
require_auth( proxy );
auto pitr = _voters.find(proxy);
//eosio_assert( pitr != _voters.end(), "proxy must have some stake first" );
//eosio_assert( !pitr->is_proxy, "account is already a proxy" );
eosio_assert( pitr->is_proxy != isproxy, "action has no effect" );
if ( pitr != _voters.end() ) {
eosio_assert( isproxy != pitr->is_proxy, "action has no effect" );
eosio_assert( !isproxy || !pitr->proxy, "account that uses a proxy is not allowed to become a proxy" );
_voters.modify( pitr, 0, [&]( auto& p ) {
p.is_proxy = isproxy;
print( " vote weight: ", p.last_vote_weight, "\n" );
......
......@@ -348,12 +348,12 @@ bytes apply_context::get_packed_transaction() {
}
void apply_context::update_db_usage( const account_name& payer, int64_t delta ) {
if( (delta > 0) ) {
if( delta > 0 ) {
if( !(privileged || payer == account_name(receiver)) ) {
require_authorization( payer );
}
trx_context.add_ram_usage(payer, delta);
}
trx_context.add_ram_usage(payer, delta);
}
......
......@@ -395,10 +395,11 @@ struct controller_impl {
etrx.set_reference_block( self.head_block_id() );
transaction_context trx_context( self, etrx, etrx.id(), start );
trx_context.deadline = deadline;
trx_context.billed_cpu_time_us = billed_cpu_time_us;
transaction_trace_ptr trace = trx_context.trace;
try {
trx_context.init_for_implicit_trx( deadline, 0 );
trx_context.init_for_implicit_trx();
trx_context.published = gto.published;
trx_context.trace->action_traces.emplace_back();
trx_context.dispatch_action( trx_context.trace->action_traces.back(), etrx.actions.back(), gto.sender );
......@@ -433,8 +434,10 @@ struct controller_impl {
bool failure_is_subjective( const fc::exception& e ) {
auto code = e.code();
return (code == tx_soft_net_usage_exceeded::code_value) ||
(code == tx_deadline_exceeded::code_value);
return (code == block_net_usage_exceeded::code_value) ||
(code == block_cpu_usage_exceeded::code_value) ||
(code == deadline_exception::code_value) ||
(code == leeway_deadline_exception::code_value);
}
transaction_trace_ptr push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
......@@ -467,11 +470,12 @@ struct controller_impl {
fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
transaction_context trx_context( self, dtrx, gto.trx_id );
trx_context.deadline = deadline;
trx_context.billed_cpu_time_us = billed_cpu_time_us;
transaction_trace_ptr trace = trx_context.trace;
flat_set<account_name> bill_to_accounts;
try {
trx_context.init_for_deferred_trx( deadline, gto.published );
trx_context.init_for_deferred_trx( gto.published );
bill_to_accounts = trx_context.bill_to_accounts;
trx_context.exec();
trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
......@@ -576,16 +580,16 @@ struct controller_impl {
transaction_trace_ptr trace;
try {
transaction_context trx_context(self, trx->trx, trx->id);
trx_context.deadline = deadline;
trx_context.billed_cpu_time_us = billed_cpu_time_us;
trace = trx_context.trace;
try {
if (implicit) {
trx_context.init_for_implicit_trx(deadline);
trx_context.init_for_implicit_trx();
} else {
trx_context.init_for_input_trx(deadline,
trx->packed_trx.get_unprunable_size(),
trx->packed_trx.get_prunable_size(),
trx->trx.signatures.size());
trx_context.init_for_input_trx( trx->packed_trx.get_unprunable_size(),
trx->packed_trx.get_prunable_size(),
trx->trx.signatures.size() );
}
trx_context.delay = fc::seconds(trx->trx.delay_sec);
......@@ -876,7 +880,7 @@ struct controller_impl {
// Update resource limits:
resource_limits.process_account_limit_updates();
const auto& chain_config = self.get_global_properties().configuration;
uint32_t max_virtual_mult = 10000;
uint32_t max_virtual_mult = 1000;
uint64_t CPU_TARGET = EOS_PERCENT(chain_config.max_block_cpu_usage, chain_config.target_block_cpu_usage_pct);
resource_limits.set_block_parameters(
{ CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, max_virtual_mult, {99, 100}, {1000, 999}},
......@@ -1066,7 +1070,8 @@ transaction_trace_ptr controller::push_transaction( const transaction_metadata_p
return my->push_transaction(trx, deadline, false, billed_cpu_time_us);
}
transaction_trace_ptr controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us ) {
transaction_trace_ptr controller::push_scheduled_transaction( const transaction_id_type& trxid, fc::time_point deadline, uint32_t billed_cpu_time_us )
{
return my->push_scheduled_transaction( trxid, deadline, billed_cpu_time_us );
}
......
......@@ -56,7 +56,7 @@ const static uint32_t rate_limiting_precision = 1000*1000;
const static uint32_t default_max_block_net_usage = 1024 * 1024; /// at 500ms blocks and 200byte trx, this enables ~10,000 TPS burst
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_max_transaction_net_usage = default_max_block_net_usage / 2;
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?
......@@ -92,7 +92,7 @@ const static uint32_t ram_usage_validation_overhead_per_account = 64
const static uint32_t fixed_net_overhead_of_packed_trx = 16; // TODO: is this reasonable?
const static uint32_t fixed_overhead_shared_vector_ram_bytes = 16; ///< overhead accounts for fixed portion of size of shared_vector field
const static uint32_t fixed_overhead_shared_vector_ram_bytes = 16; ///< overhead accounts for fixed portion of size of shared_vector field
const static uint32_t overhead_per_row_per_index_ram_bytes = 32; ///< overhead accounts for basic tracking structures in a row per index
const static uint32_t overhead_per_account_ram_bytes = 2*1024; ///< overhead accounts for basic account storage and pre-pays features like account recovery
const static uint32_t setcode_ram_bytes_multiplier = 10; ///< multiplier on contract size to account for multiple copies and cached compilation
......
......@@ -203,16 +203,16 @@ namespace eosio { namespace chain {
3080001, "account using more than allotted RAM usage" )
FC_DECLARE_DERIVED_EXCEPTION( tx_net_usage_exceeded, resource_exhausted_exception,
3080002, "transaction exceeded the current network usage limit imposed on the transaction" )
FC_DECLARE_DERIVED_EXCEPTION( tx_soft_net_usage_exceeded, resource_exhausted_exception,
FC_DECLARE_DERIVED_EXCEPTION( block_net_usage_exceeded, resource_exhausted_exception,
3080003, "transaction network usage is too much for the remaining allowable usage of the current block" )
FC_DECLARE_DERIVED_EXCEPTION( tx_cpu_usage_exceeded, resource_exhausted_exception,
3080004, "transaction exceeded the current CPU usage limit imposed on the transaction" )
FC_DECLARE_DERIVED_EXCEPTION( tx_soft_cpu_usage_exceeded, resource_exhausted_exception,
FC_DECLARE_DERIVED_EXCEPTION( block_cpu_usage_exceeded, resource_exhausted_exception,
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,
FC_DECLARE_DERIVED_EXCEPTION( deadline_exception, 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( leeway_deadline_exception, deadline_exception,
3081001, "transaction reached the deadline set due to leeway on account CPU limits" )
FC_DECLARE_DERIVED_EXCEPTION( authorization_exception, chain_exception,
3090000, "Authorization exception" )
......
......@@ -27,9 +27,9 @@ namespace eosio { namespace chain { namespace resource_limits {
};
struct account_resource_limit {
int64_t current_per_block = 0;
int64_t max_per_block = 0;
int64_t guaranteed_per_day = 0;
int64_t used = 0; ///< quantity used in current window
int64_t available = 0; ///< quantity available in current window (based upon fractional reserve)
int64_t max_gauranteed = 0; ///< max per window under 100% congestion
};
class resource_limits_manager {
......@@ -76,4 +76,4 @@ namespace eosio { namespace chain { namespace resource_limits {
};
} } } /// eosio::chain
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (current_per_block)(max_per_block)(guaranteed_per_day) )
FC_REFLECT( eosio::chain::resource_limits::account_resource_limit, (used)(available)(max_gauranteed) )
......@@ -63,8 +63,6 @@ namespace eosio { namespace chain { namespace resource_limits {
EOS_ASSERT(std::numeric_limits<decltype(value_ex)>::max() - value_ex >= value_ex_contrib, rate_limiting_state_inconsistent, "Overflow in accumulated value when adding usage!");
if( last_ordinal != ordinal ) {
if( ordinal <= last_ordinal )
wdump((ordinal)(last_ordinal));
FC_ASSERT( ordinal > last_ordinal, "new ordinal cannot be less than the previous ordinal" );
if( (uint64_t)last_ordinal + window_size > (uint64_t)ordinal ) {
const auto delta = ordinal - last_ordinal; // clearly 0 < delta < window_size
......
......@@ -15,17 +15,13 @@ namespace eosio { namespace chain {
const transaction_id_type& trx_id,
fc::time_point start = fc::time_point::now() );
void init_for_implicit_trx( fc::time_point deadline,
uint64_t initial_net_usage = 0
);
void init_for_implicit_trx( uint64_t initial_net_usage = 0 );
void init_for_input_trx( fc::time_point deadline,
uint64_t packed_trx_unprunable_size,
void init_for_input_trx( uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size,
uint32_t num_signatures );
void init_for_deferred_trx( fc::time_point deadline,
fc::time_point published );
void init_for_deferred_trx( fc::time_point published );
void exec();
void finalize();
......@@ -50,6 +46,8 @@ 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 u, bool check_minimum = true )const;
/// Fields:
public:
......@@ -61,16 +59,12 @@ namespace eosio { namespace chain {
fc::time_point start;
fc::time_point published;
fc::time_point deadline = fc::time_point::maximum();
vector<action_receipt> executed;
flat_set<account_name> bill_to_accounts;
flat_set<account_name> validate_ram_usage;
/// 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;
/// 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;
......@@ -78,14 +72,22 @@ namespace eosio { namespace chain {
bool is_input = false;
bool apply_context_free = true;
uint32_t billed_cpu_time_us = 0;
fc::time_point deadline = fc::time_point::maximum();
fc::microseconds leeway = fc::microseconds(1000);
int64_t billed_cpu_time_us = 0;
private:
bool is_initialized = false;
uint64_t net_limit = 0;
bool net_limit_due_to_block = true;
uint64_t eager_net_limit = 0;
uint64_t& net_usage; /// reference to trace->net_usage
bool net_limit_due_to_block = false;
bool cpu_limit_due_to_block = false;
bool is_initialized = false;
fc::microseconds objective_duration_limit;
bool objective_duration_limit_due_to_block = true;
int64_t deadline_exception_code = block_cpu_usage_exceeded::code_value;
};
} }
......@@ -87,40 +87,52 @@ void resource_limits_manager::add_transaction_usage(const flat_set<account_name>
for( const auto& a : accounts ) {
const auto& usage = _db.get<resource_usage_object,by_owner>( a );
const auto& limits = _db.get<resource_limits_object,by_owner>( boost::make_tuple(false, a));
int64_t unused;
int64_t net_weight;
int64_t cpu_weight;
get_account_limits( a, unused, net_weight, cpu_weight );
_db.modify( usage, [&]( auto& bu ){
bu.net_usage.add( net_usage, time_slot, config.account_net_usage_average_window );
bu.cpu_usage.add( cpu_usage, time_slot, config.account_cpu_usage_average_window );
});
if (limits.cpu_weight >= 0) {
uint128_t consumed_cpu_ex = usage.cpu_usage.consumed * config::rate_limiting_precision;
uint128_t capacity_cpu_ex = state.virtual_cpu_limit * config::rate_limiting_precision;
if( cpu_weight >= 0 && state.total_cpu_weight > 0 ) {
uint128_t window_size = config.account_cpu_usage_average_window;
auto virtual_network_capacity_in_window = state.virtual_cpu_limit * window_size;
auto cpu_used_in_window = (usage.cpu_usage.value_ex * window_size) / config::rate_limiting_precision;
uint128_t user_weight = cpu_weight;
uint128_t all_user_weight = state.total_cpu_weight;
auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;
EOS_ASSERT( state.total_cpu_weight > 0 && (consumed_cpu_ex * state.total_cpu_weight) <= (limits.cpu_weight * capacity_cpu_ex),
EOS_ASSERT( cpu_used_in_window <= max_user_use_in_window,
tx_cpu_usage_exceeded,
"authorizing account '${n}' has insufficient cpu resources for this transaction",
("n", name(a))
("consumed", (double)consumed_cpu_ex/(double)config::rate_limiting_precision)
("cpu_weight", limits.cpu_weight)
("virtual_cpu_capacity", (double)state.virtual_cpu_limit )
("total_cpu_weight", state.total_cpu_weight)
);
("n", name(a))
("cpu_used_in_window",cpu_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
}
if (limits.net_weight >= 0) {
uint128_t consumed_net_ex = usage.net_usage.consumed * config::rate_limiting_precision;
uint128_t capacity_net_ex = state.virtual_net_limit * config::rate_limiting_precision;
if( net_weight >= 0 && state.total_net_weight > 0) {
uint128_t window_size = config.account_net_usage_average_window;
auto virtual_network_capacity_in_window = state.virtual_net_limit * window_size;
auto net_used_in_window = (usage.net_usage.value_ex * window_size) / config::rate_limiting_precision;
uint128_t user_weight = net_weight;
uint128_t all_user_weight = state.total_net_weight;
auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;
EOS_ASSERT( state.total_net_weight > 0 && (consumed_net_ex * state.total_net_weight) <= (limits.net_weight * capacity_net_ex),
EOS_ASSERT( net_used_in_window <= max_user_use_in_window,
tx_net_usage_exceeded,
"authorizing account '${n}' has insufficient net resources for this transaction",
("n", name(a))
("consumed", (double)consumed_net_ex/(double)config::rate_limiting_precision)
("net_weight", limits.net_weight)
("virtual_net_capacity", (double)state.virtual_net_limit )
("total_net_weight", state.total_net_weight)
);
("n", name(a))
("net_used_in_window",net_used_in_window)
("max_user_use_in_window",max_user_use_in_window) );
}
}
......@@ -314,10 +326,41 @@ uint64_t resource_limits_manager::get_block_net_limit() const {
}
int64_t resource_limits_manager::get_account_cpu_limit( const account_name& name ) const {
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
const auto& limits = _db.get<resource_limits_object, by_owner>(boost::make_tuple(false, name));
if (limits.cpu_weight < 0) {
const auto& config = _db.get<resource_limits_config_object>();
int64_t unused;
int64_t cpu_weight;
get_account_limits( name, unused, unused, cpu_weight );
if( cpu_weight < 0 || state.total_cpu_weight == 0 ) {
return -1;
}
uint128_t window_size = config.account_cpu_usage_average_window;
auto virtual_cpu_capacity_in_window = state.virtual_cpu_limit * window_size;
uint128_t user_weight = cpu_weight;
uint128_t all_user_weight = state.total_cpu_weight;
auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight;
auto cpu_used_in_window = (usage.cpu_usage.value_ex * window_size) / config::rate_limiting_precision;
if( max_user_use_in_window <= cpu_used_in_window ) return 0;
return max_user_use_in_window - cpu_used_in_window;
/*
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
int64_t x;
int64_t cpu_weight;
get_account_limits( name, x, x, cpu_weight );
if( cpu_weight < 0 ) {
return -1;
}
......@@ -327,101 +370,108 @@ int64_t resource_limits_manager::get_account_cpu_limit( const account_name& name
uint128_t consumed_ex = (uint128_t)usage.cpu_usage.consumed * (uint128_t)config::rate_limiting_precision;
uint128_t virtual_capacity_ex = (uint128_t)state.virtual_cpu_limit * (uint128_t)config::rate_limiting_precision;
uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight;
uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * cpu_weight) / (uint128_t)total_cpu_weight;
//idump((virtual_capacity_ex)(total_cpu_weight)(limits.cpu_weight)(usable_capacity_ex)(consumed_ex)(config::rate_limiting_precision) );
if (usable_capacity_ex < consumed_ex) {
if( usable_capacity_ex < consumed_ex ) {
return 0;
}
return (int64_t)((usable_capacity_ex - consumed_ex) / (uint128_t)config::rate_limiting_precision);
*/
}
account_resource_limit resource_limits_manager::get_account_cpu_limit_ex( const account_name& name ) const {
const auto& cfg = _db.get<resource_limits_config_object>();
const auto& config = _db.get<resource_limits_config_object>();
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
const auto& limits = _db.get<resource_limits_object, by_owner>(boost::make_tuple(false, name));
if (limits.cpu_weight < 0) {
int64_t x;
int64_t cpu_weight;
get_account_limits( name, x, x, cpu_weight );
if( cpu_weight < 0 || state.total_cpu_weight == 0 ) {
return { -1, -1, -1 };
}
auto total_cpu_weight = state.total_cpu_weight;
if( total_cpu_weight == 0 ) total_cpu_weight = 1;
account_resource_limit arl;
uint128_t consumed_ex = (uint128_t)usage.cpu_usage.consumed * (uint128_t)config::rate_limiting_precision;
uint128_t virtual_capacity_ex = (uint128_t)state.virtual_cpu_limit * (uint128_t)config::rate_limiting_precision;
uint128_t window_size = config.account_cpu_usage_average_window;
uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight;
auto virtual_cpu_capacity_in_window = state.virtual_cpu_limit * window_size;
uint128_t user_weight = cpu_weight;
uint128_t all_user_weight = state.total_cpu_weight;
wdump((cfg.cpu_limit_parameters.target));
uint128_t real_capacity_ex = (uint128_t)cfg.cpu_limit_parameters.target * (uint128_t)config::rate_limiting_precision;
uint128_t guaranteed_capacity_ex = (uint128_t)(real_capacity_ex * limits.cpu_weight) / (uint128_t)total_cpu_weight;
auto max_user_use_in_window = (virtual_cpu_capacity_in_window * user_weight) / all_user_weight;
auto cpu_used_in_window = (usage.cpu_usage.value_ex * window_size) / config::rate_limiting_precision;
uint128_t blocks_per_day = 86400 * 1000 / config::block_interval_ms;
if( max_user_use_in_window <= cpu_used_in_window )
arl.available = 0;
else
arl.available = max_user_use_in_window - cpu_used_in_window;
if (usable_capacity_ex < consumed_ex) {
consumed_ex = usable_capacity_ex;
}
return { (int64_t)(std::min(usable_capacity_ex - consumed_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision),
(int64_t)(std::min(usable_capacity_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision),
(int64_t)(guaranteed_capacity_ex * blocks_per_day / cfg.cpu_limit_parameters.periods / (uint128_t)config::rate_limiting_precision)
};
arl.used = cpu_used_in_window;
return arl;
}
int64_t resource_limits_manager::get_account_net_limit( const account_name& name ) const {
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
const auto& limits = _db.get<resource_limits_object, by_owner>(boost::make_tuple(false, name));
if (limits.net_weight < 0) {
const auto& config = _db.get<resource_limits_config_object>();
int64_t unused;
int64_t net_weight;
get_account_limits( name, unused, net_weight, unused );
if( net_weight < 0 ) {
return -1;
}
uint128_t consumed_ex = (uint128_t)usage.net_usage.consumed * (uint128_t)config::rate_limiting_precision;
uint128_t virtual_capacity_ex = (uint128_t)state.virtual_net_limit * (uint128_t)config::rate_limiting_precision;
auto total_net_weight = state.total_net_weight;
if( total_net_weight == 0 ) total_net_weight = 1;
uint128_t window_size = config.account_net_usage_average_window;
uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; // max
auto virtual_network_capacity_in_window = state.virtual_net_limit * window_size;
uint128_t user_weight = net_weight;
uint128_t all_user_weight = state.total_net_weight;
if (usable_capacity_ex < consumed_ex) {
return 0;
}
auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;
auto net_used_in_window = (usage.net_usage.value_ex * window_size) / config::rate_limiting_precision;
return (int64_t)((usable_capacity_ex - consumed_ex) / (uint128_t)config::rate_limiting_precision);
if( max_user_use_in_window <= net_used_in_window ) return 0;
return max_user_use_in_window - net_used_in_window;
}
account_resource_limit resource_limits_manager::get_account_net_limit_ex( const account_name& name ) const {
const auto& cfg = _db.get<resource_limits_config_object>();
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
const auto& limits = _db.get<resource_limits_object, by_owner>(boost::make_tuple(false, name));
if (limits.net_weight < 0) {
const auto& config = _db.get<resource_limits_config_object>();
const auto& state = _db.get<resource_limits_state_object>();
const auto& usage = _db.get<resource_usage_object, by_owner>(name);
int64_t x;
int64_t net_weight;
get_account_limits( name, x, net_weight, x );
if( net_weight < 0 || state.total_net_weight == 0) {
return { -1, -1, -1 };
}
auto total_net_weight = state.total_net_weight;
if( total_net_weight == 0 ) total_net_weight = 1;
account_resource_limit arl;
uint128_t consumed_ex = (uint128_t)usage.net_usage.consumed * (uint128_t)config::rate_limiting_precision;
uint128_t virtual_capacity_ex = (uint128_t)state.virtual_net_limit * (uint128_t)config::rate_limiting_precision;
uint128_t window_size = config.account_net_usage_average_window;
uint128_t usable_capacity_ex = (uint128_t)(virtual_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight; // max
auto virtual_network_capacity_in_window = state.virtual_net_limit * window_size;
uint128_t user_weight = net_weight;
uint128_t all_user_weight = state.total_net_weight;
uint128_t real_capacity_ex = (uint128_t)cfg.net_limit_parameters.target * (uint128_t)config::rate_limiting_precision;
uint128_t guaranteed_capacity_ex = (uint128_t)(real_capacity_ex * limits.net_weight) / (uint128_t)total_net_weight;
auto max_user_use_in_window = (virtual_network_capacity_in_window * user_weight) / all_user_weight;
auto net_used_in_window = (usage.net_usage.value_ex * window_size) / config::rate_limiting_precision;
uint128_t blocks_per_day = 86400 * 1000 / config::block_interval_ms;
if( max_user_use_in_window <= net_used_in_window )
arl.available = 0;
else
arl.available = max_user_use_in_window - net_used_in_window;
if (usable_capacity_ex < consumed_ex) {
consumed_ex = usable_capacity_ex;
}
return { (int64_t)(std::min(usable_capacity_ex - consumed_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision),
(int64_t)(std::min(usable_capacity_ex, real_capacity_ex) / (uint128_t)config::rate_limiting_precision),
(int64_t)(guaranteed_capacity_ex * blocks_per_day / cfg.net_limit_parameters.periods / (uint128_t)config::rate_limiting_precision)
};
arl.used = net_used_in_window;
return arl;
}
......
......@@ -29,91 +29,113 @@ namespace eosio { namespace chain {
void transaction_context::init(uint64_t initial_net_usage )
{
FC_ASSERT( !is_initialized, "cannot initialize twice" );
const static int64_t large_number_no_overflow = std::numeric_limits<int64_t>::max()/2;
// Record accounts to be billed for network and CPU usage
uint64_t determine_payers_cpu_cost = 0;
for( const auto& act : trx.actions ) {
for( const auto& auth : act.authorization ) {
bill_to_accounts.insert( auth.actor );
determine_payers_cpu_cost += config::determine_payers_cpu_overhead_per_authorization;
}
}
validate_ram_usage.reserve( bill_to_accounts.size() );
// Calculate network and CPU usage limits and initial usage:
auto original_deadline = deadline;
// Start with limits set in dynamic configuration
const auto& cfg = control.get_global_properties().configuration;
max_net = cfg.max_transaction_net_usage;
auto& rl = control.get_mutable_resource_limits_manager();
// Potentially lower limits to what is optionally set in the transaction header
uint64_t trx_specified_net_usage_limit = static_cast<uint64_t>(trx.max_net_usage_words.value)*8;
if( trx_specified_net_usage_limit > 0 )
max_net = std::min( max_net, trx_specified_net_usage_limit );
net_limit = rl.get_block_net_limit();
eager_net_limit = max_net;
objective_duration_limit = fc::microseconds( rl.get_block_cpu_limit() );
deadline = start + objective_duration_limit;
// 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 );
// Check if deadline is limited by block deadline or caller-set deadline
if( original_deadline <= deadline ) {
deadline = original_deadline;
deadline_exception_code = deadline_exception::code_value;
}
uint64_t block_net_limit = rl.get_block_net_limit();
uint64_t block_cpu_limit = rl.get_block_cpu_limit();
// Possibly lower net_limit to the maximum net usage a transaction is allowed to be billed
if( cfg.max_transaction_net_usage <= net_limit ) {
net_limit = cfg.max_transaction_net_usage;
net_limit_due_to_block = false;
}
if( !billed_cpu_time_us ) {
auto potential_deadline = fc::time_point::now() + fc::microseconds(block_cpu_limit);
if( potential_deadline < deadline ) deadline = potential_deadline;
// Possibly lower net_limit to optional limit set in the transaction header
uint64_t trx_specified_net_usage_limit = static_cast<uint64_t>(trx.max_net_usage_words.value) * 8;
if( trx_specified_net_usage_limit > 0 && trx_specified_net_usage_limit <= net_limit ) {
net_limit = trx_specified_net_usage_limit;
net_limit_due_to_block = false;
}
if( block_net_limit < eager_net_limit ) {
eager_net_limit = block_net_limit;
net_limit_due_to_block = true;
// Possibly lower objective_duration_limit to optional limit set in transaction header
if( trx.max_cpu_usage_ms > 0 ) {
auto trx_specified_cpu_usage_limit = fc::milliseconds(trx.max_cpu_usage_ms);
if( trx_specified_cpu_usage_limit <= objective_duration_limit ) {
objective_duration_limit = trx_specified_cpu_usage_limit;
objective_duration_limit_due_to_block = false;
}
}
// Initial billing for network usage
if( initial_net_usage > 0 )
add_net_usage( initial_net_usage );
// Possibly limit deadline if objective_duration_limit is not due to the block and does not exceed current delta
if( !objective_duration_limit_due_to_block && objective_duration_limit <= (deadline - start) ) {
deadline = start + objective_duration_limit;
deadline_exception_code = tx_cpu_usage_exceeded::code_value;
}
eager_net_limit = max_net;
net_limit_due_to_block = false;
if( billed_cpu_time_us > 0 )
validate_cpu_usage_to_bill( billed_cpu_time_us, false ); // Fail early if the amount to be billed is too high
// Lower limits to what the billed accounts can afford to pay
// Record accounts to be billed for network and CPU usage
for( const auto& act : trx.actions ) {
for( const auto& auth : act.authorization ) {
bill_to_accounts.insert( auth.actor );
}
}
validate_ram_usage.reserve( bill_to_accounts.size() );
// Update usage values of accounts to reflect new time
rl.add_transaction_usage( bill_to_accounts, 0, 0, block_timestamp_type(control.pending_block_time()).slot );
// Calculate the highest network usage and CPU time that all of the billed accounts can afford to be billed
int64_t account_net_limit = large_number_no_overflow;
int64_t account_cpu_limit = large_number_no_overflow;
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
account_net_limit = std::min( account_net_limit, net_limit );
auto cpu_limit = rl.get_account_cpu_limit(a);
auto potential_deadline = fc::time_point::now() + fc::microseconds(block_cpu_limit);
if( potential_deadline < deadline ) deadline = potential_deadline;
if( cpu_limit >= 0 )
account_cpu_limit = std::min( account_cpu_limit, cpu_limit );
}
eager_net_limit += cfg.net_usage_leeway;
eager_net_limit = std::min(eager_net_limit, max_net);
eager_net_limit = net_limit;
// Possible lower eager_net_limit to what the billed accounts can pay plus some (objective) leeway
auto new_eager_net_limit = std::min( eager_net_limit, static_cast<uint64_t>(account_net_limit + cfg.net_usage_leeway) );
if( new_eager_net_limit < eager_net_limit ) {
eager_net_limit = new_eager_net_limit;
net_limit_due_to_block = false;
}
if( block_net_limit < eager_net_limit ) {
eager_net_limit = block_net_limit;
net_limit_due_to_block = true;
// Possibly limit deadline if the duration accounts can be billed for (+ a subjective leeway) does not exceed current delta
if( ( fc::microseconds(account_cpu_limit) + leeway ) <= (deadline - start) ) {
deadline = start + fc::microseconds(account_cpu_limit) + leeway;
deadline_exception_code = leeway_deadline_exception::code_value;
}
// Round down network and CPU usage limits so that comparison to actual usage is more efficient
eager_net_limit = (eager_net_limit/8)*8; // Round down to nearest multiple of word size (8 bytes)
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
if( initial_net_usage > 0 )
check_net_usage(); // Fail early if current net usage is already greater than the calculated limit
add_net_usage( initial_net_usage ); // Fail early if current net usage is already greater than the calculated limit
if( billed_cpu_time_us > 0 )
deadline = original_deadline; // Only change deadline if billed_cpu_time_us is not set
check_time(); // Fail early if deadline has already been exceeded
is_initialized = true;
}
void transaction_context::init_for_implicit_trx( fc::time_point d, uint64_t initial_net_usage )
void transaction_context::init_for_implicit_trx( uint64_t initial_net_usage )
{
published = control.pending_block_time();
deadline = d;
init( initial_net_usage );
}
void transaction_context::init_for_input_trx( fc::time_point d,
uint64_t packed_trx_unprunable_size,
void transaction_context::init_for_input_trx( uint64_t packed_trx_unprunable_size,
uint64_t packed_trx_prunable_size,
uint32_t num_signatures )
{
......@@ -140,7 +162,6 @@ namespace eosio { namespace chain {
}
published = control.pending_block_time();
deadline = d;
is_input = true;
control.validate_expiration( trx );
control.validate_tapos( trx );
......@@ -149,11 +170,9 @@ namespace eosio { namespace chain {
record_transaction( id, trx.expiration ); /// checks for dupes
}
void transaction_context::init_for_deferred_trx( fc::time_point d,
fc::time_point p )
void transaction_context::init_for_deferred_trx( fc::time_point p )
{
published = p;
deadline = d;
trace->scheduled = true;
apply_context_free = false;
init( 0 );
......@@ -181,6 +200,7 @@ namespace eosio { namespace chain {
void transaction_context::finalize() {
FC_ASSERT( is_initialized, "must first initialize" );
const static int64_t large_number_no_overflow = std::numeric_limits<int64_t>::max()/2;
if( is_input ) {
auto& am = control.get_mutable_authorization_manager();
......@@ -196,27 +216,43 @@ namespace eosio { namespace chain {
rl.verify_account_ram_usage( a );
}
eager_net_limit = max_net;
net_limit_due_to_block = false;
// Lower limits to what the billed accounts can afford to pay
// Calculate the new highest network usage and CPU time that all of the billed accounts can afford to be billed
int64_t account_net_limit = large_number_no_overflow;
int64_t account_cpu_limit = large_number_no_overflow;
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
account_net_limit = std::min( account_net_limit, net_limit );
auto cpu_limit = rl.get_account_cpu_limit(a);
if( cpu_limit >= 0 )
account_cpu_limit = std::min( account_cpu_limit, cpu_limit );
}
// Possibly lower net_limit to what the billed accounts can pay
if( static_cast<uint64_t>(account_net_limit) <= net_limit ) {
net_limit = static_cast<uint64_t>(account_net_limit);
net_limit_due_to_block = false;
}
// Possibly lower objective_duration_limit to what the billed accounts can pay
if( account_cpu_limit <= objective_duration_limit.count() ) {
objective_duration_limit = fc::microseconds(account_cpu_limit);
objective_duration_limit_due_to_block = false;
}
net_usage = ((net_usage + 7)/8)*8; // Round up to nearest multiple of word size (8 bytes)
eager_net_limit = net_limit;
check_net_usage();
trace->elapsed = fc::time_point::now() - start;
if( !billed_cpu_time_us )
billed_cpu_time_us = trace->elapsed.count();
if( billed_cpu_time_us == 0 )
billed_cpu_time_us = std::max( trace->elapsed.count(), static_cast<int64_t>(config::default_min_transaction_cpu_usage_us) );
validate_cpu_usage_to_bill( billed_cpu_time_us );
rl.add_transaction_usage( bill_to_accounts, billed_cpu_time_us, net_usage,
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
}
......@@ -227,22 +263,60 @@ namespace eosio { namespace chain {
void transaction_context::check_net_usage()const {
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}",
("actual_net_usage", net_usage)("net_usage_limit", max_net) );
if( net_limit_due_to_block ) {
EOS_THROW( block_net_usage_exceeded,
"not enough space left in block: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
} else {
EOS_THROW( tx_net_usage_exceeded,
"net usage of transaction is too high: ${actual_net_usage} > ${net_usage_limit}",
("actual_net_usage", net_usage)("net_usage_limit", max_net) );
"net usage of transaction is too high: ${net_usage} > ${net_limit}",
("net_usage", net_usage)("net_limit", eager_net_limit) );
}
}
}
void transaction_context::check_time()const {
EOS_ASSERT( BOOST_LIKELY(fc::time_point::now() <= deadline), tx_deadline_exceeded,
"deadline exceeded",
("now",fc::time_point::now())("deadline",deadline)("start",start) );
auto now = fc::time_point::now();
if( BOOST_UNLIKELY( now > deadline ) ) {
if( billed_cpu_time_us > 0 || deadline_exception_code == deadline_exception::code_value ) {
EOS_THROW( deadline_exception, "deadline exceeded", ("now", now)("deadline", deadline)("start", start) );
} else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) {
EOS_THROW( block_cpu_usage_exceeded,
"not enough time left in block to complete executing transaction",
("now", now)("deadline", deadline)("start", start) );
} else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) {
EOS_THROW( tx_cpu_usage_exceeded,
"transaction was executing for too long",
("now", now)("deadline", deadline)("start", start) );
} else if( deadline_exception_code == leeway_deadline_exception::code_value ) {
EOS_THROW( leeway_deadline_exception,
"the transaction was unable to complete by deadline, "
"but it is possible it could have succeeded if it were allow to run to completion",
("now", now)("deadline", deadline)("start", start) );
}
FC_ASSERT( false, "unexpected deadline exception code" );
}
}
void transaction_context::validate_cpu_usage_to_bill( int64_t billed_us, bool check_minimum )const {
#warning make min_transaction_cpu_us into a configuration parameter
EOS_ASSERT( !check_minimum || billed_us >= config::default_min_transaction_cpu_usage_us, transaction_exception,
"cannot bill CPU time less than the minimum of ${min_billable} us",
("min_billable", config::default_min_transaction_cpu_usage_us)("billed_cpu_time_us", billed_us)
);
if( objective_duration_limit_due_to_block ) {
EOS_ASSERT( billed_us <= objective_duration_limit.count(),
block_cpu_usage_exceeded,
"billed CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)",
("billed", billed_us)("billable", objective_duration_limit.count())
);
} else {
EOS_ASSERT( billed_us <= objective_duration_limit.count(),
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", objective_duration_limit.count())
);
}
}
void transaction_context::add_ram_usage( account_name account, int64_t ram_delta ) {
......@@ -260,9 +334,6 @@ namespace eosio { namespace chain {
try {
acontext.exec();
} catch( const action_cpu_usage_exceeded& e ) {
trace = move(acontext.trace);
FC_ASSERT(false, "should not have reached here" );
} catch( ... ) {
trace = move(acontext.trace);
throw;
......
......@@ -1208,7 +1208,7 @@ class memory_api : public context_aware_api {
:context_aware_api(ctx,true){}
char* memcpy( array_ptr<char> dest, array_ptr<const char> src, size_t length) {
EOS_ASSERT((abs((ptrdiff_t)dest.value - (ptrdiff_t)src.value)) >= length,
EOS_ASSERT((std::abs((ptrdiff_t)dest.value - (ptrdiff_t)src.value)) >= length,
overlapping_memory_error, "memcpy can only accept non-aliasing pointers");
return (char *)::memcpy(dest, src, length);
}
......
Subproject commit 4ebab558f506f13457317fe9f0ca5b79511b76a1
Subproject commit cb51952ae12e550959fa5c4cf9bec5fa5c454b5a
......@@ -72,7 +72,7 @@ namespace eosio { namespace testing {
static const uint32_t DEFAULT_EXPIRATION_DELTA = 6;
static const uint32_t DEFAULT_BILLED_CPU_TIME_US = 5000;
static const uint32_t DEFAULT_BILLED_CPU_TIME_US = 2000;
void init(bool push_genesis = true);
void init(controller::config config);
......@@ -87,8 +87,8 @@ namespace eosio { namespace testing {
void produce_blocks_until_end_of_round();
signed_block_ptr push_block(signed_block_ptr b);
transaction_trace_ptr push_transaction( packed_transaction& trx, uint32_t skip_flag = 0/*skip_nothing */, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US );
transaction_trace_ptr push_transaction( signed_transaction& trx, uint32_t skip_flag = 0/*skip_nothing*/, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US );
transaction_trace_ptr push_transaction( packed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US );
transaction_trace_ptr push_transaction( signed_transaction& trx, fc::time_point deadline = fc::time_point::maximum(), uint32_t billed_cpu_time_us = DEFAULT_BILLED_CPU_TIME_US );
action_result push_action(action&& cert_act, uint64_t authorizer); // TODO/QUESTION: Is this needed?
transaction_trace_ptr push_action( const account_name& code,
......
......@@ -243,7 +243,6 @@ namespace eosio { namespace testing {
}
transaction_trace_ptr base_tester::push_transaction( packed_transaction& trx,
uint32_t skip_flag,
fc::time_point deadline,
uint32_t billed_cpu_time_us
)
......@@ -257,7 +256,6 @@ namespace eosio { namespace testing {
} FC_CAPTURE_AND_RETHROW( (transaction_header(trx.get_transaction())) ) }
transaction_trace_ptr base_tester::push_transaction( signed_transaction& trx,
uint32_t skip_flag,
fc::time_point deadline,
uint32_t billed_cpu_time_us
)
......@@ -276,7 +274,7 @@ namespace eosio { namespace testing {
if( r->except_ptr ) std::rethrow_exception( r->except_ptr );
if( r->except) throw *r->except;
return r;
} FC_CAPTURE_AND_RETHROW( (transaction_header(trx)) ) }
} FC_CAPTURE_AND_RETHROW( (transaction_header(trx))(billed_cpu_time_us) ) }
typename base_tester::action_result base_tester::push_action(action&& act, uint64_t authorizer) {
signed_transaction trx;
......@@ -291,6 +289,7 @@ namespace eosio { namespace testing {
try {
push_transaction(trx);
} catch (const fc::exception& ex) {
edump((ex.to_detail_string()));
return error(ex.top_message()); // top_message() is assumed by many tests; otherwise they fail
//return error(ex.to_detail_string());
}
......
......@@ -45,9 +45,10 @@ using namespace eosio::chain::plugin_interface;
namespace {
bool failure_is_subjective(const fc::exception& e, bool deadline_is_subjective) {
auto code = e.code();
return (code == tx_soft_cpu_usage_exceeded::code_value) ||
(code == tx_soft_net_usage_exceeded::code_value) ||
(code == tx_deadline_exceeded::code_value && deadline_is_subjective);
return (code == block_cpu_usage_exceeded::code_value) ||
(code == block_net_usage_exceeded::code_value) ||
(code == deadline_exception::code_value && deadline_is_subjective) ||
(code == leeway_deadline_exception::code_value && deadline_is_subjective);
}
}
......
......@@ -411,7 +411,7 @@ chain::action create_action(const vector<permission_level>& authorization, const
("args", args);
auto result = call(json_to_bin_func, arg);
wlog("result=${r}",("r",result));
wdump((result)(arg));
return chain::action{authorization, code, act, result.get_object()["binargs"].as<bytes>()};
}
......@@ -806,7 +806,7 @@ struct create_account_subcommand {
createAccount->add_option("creator", creator, localized("The name of the account creating the new account"))->required();
createAccount->add_option("name", account_name, localized("The name of the new account"))->required();
createAccount->add_option("OwnerKey", owner_key_str, localized("The owner public key for the new account"))->required();
createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the new account"))->required();
createAccount->add_option("ActiveKey", active_key_str, localized("The active public key for the new account"));
if (!simple) {
createAccount->add_option("--stake-net", stake_net,
......@@ -824,6 +824,8 @@ struct create_account_subcommand {
add_standard_transaction_options(createAccount);
createAccount->set_callback([this] {
if( !active_key_str.size() )
active_key_str = owner_key_str;
public_key_type owner_key, active_key;
try {
owner_key = public_key_type(owner_key_str);
......@@ -963,6 +965,7 @@ struct delegate_bandwidth_subcommand {
string stake_net_amount;
string stake_cpu_amount;
string stake_storage_amount;
bool transfer = false;
delegate_bandwidth_subcommand(CLI::App* actionRoot) {
auto delegate_bandwidth = actionRoot->add_subcommand("delegatebw", localized("Delegate bandwidth"));
......@@ -970,6 +973,7 @@ struct delegate_bandwidth_subcommand {
delegate_bandwidth->add_option("receiver", receiver_str, localized("The account to receive the delegated bandwidth"))->required();
delegate_bandwidth->add_option("stake_net_quantity", stake_net_amount, localized("The amount of EOS to stake for network bandwidth"))->required();
delegate_bandwidth->add_option("stake_cpu_quantity", stake_cpu_amount, localized("The amount of EOS to stake for CPU bandwidth"))->required();
delegate_bandwidth->add_flag("--transfer", transfer, localized("specify to stake in name of receiver rather than in name of from"))->required();
add_standard_transaction_options(delegate_bandwidth);
delegate_bandwidth->set_callback([this] {
......@@ -977,7 +981,9 @@ struct delegate_bandwidth_subcommand {
("from", from_str)
("receiver", receiver_str)
("stake_net_quantity", to_asset(stake_net_amount))
("stake_cpu_quantity", to_asset(stake_cpu_amount));
("stake_cpu_quantity", to_asset(stake_cpu_amount))
("transfer", transfer)
;
wdump((act_payload));
send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(delegatebw), act_payload)});
});
......@@ -1046,7 +1052,7 @@ struct sellram_subcommand {
fc::variant act_payload = fc::mutable_variant_object()
("account", receiver_str)
("bytes", amount);
send_actions({create_action({permission_level{from_str,config::active_name}}, config::system_account_name, N(sellram), act_payload)});
send_actions({create_action({permission_level{receiver_str,config::active_name}}, config::system_account_name, N(sellram), act_payload)});
});
}
};
......@@ -1185,16 +1191,50 @@ void get_account( const string& accountName, bool json_format ) {
<< indent << "delegated:" << std::setw(17) << net_others
<< std::string(11, ' ') << "(total staked delegated to account from others)" << std::endl;
}
std::cout << indent << "current:" << std::setw(15) << ("~"+std::to_string(res.net_limit.current_per_block)) << " bytes/block"
string unit = "bytes";
double net_usage = res.net_limit.available;
if( res.net_limit.available >= 1024*1024*1024 ){
unit = "Gb";
net_usage /= 1024*1024*1024;
} else if( res.net_limit.available >= 1024*1024 ){
unit = "Mb";
net_usage /= 1024*1024;
} else if( res.net_limit.available >= 1024 ) {
unit = "Kb";
net_usage /= 1024;
}
std::cout << std::fixed << setprecision(3);
std::cout << indent << "used:" << std::setw(15) << ("~"+std::to_string(res.net_limit.used)) << " bytes (past 3 days)"
<< std::string(3, ' ') << "(assuming current congestion and current usage)" << std::endl
<< indent << "max:" << std::setw(19) << ("~"+std::to_string(res.net_limit.max_per_block)) << " bytes/block"
<< indent << "available:" << std::setw(19) << ("~"+std::to_string(net_usage)) << " "<<unit
<< std::string(3, ' ') << "(assuming current congestion and 0 usage in current window)" << std::endl
/*
<< indent << "guaranteed: " << std::setw(11) << res.net_limit.guaranteed_per_day << " bytes/day"
<< std::string(5, ' ') << "(assuming 100% congestion and 0 usage in current window)" << std::endl
*/
<< std::endl;
std::cout << "cpu bandwidth:" << std::endl;
double cpu_avail = res.cpu_limit.available/1000000.;
string cunit = "sec";
if( cpu_avail > 60*60*24 ) {
cunit = "days";
cpu_avail /= 60*60*24;
} else if( cpu_avail > 60*60 ) {
cunit = "hr";
cpu_avail /= 60*60;
} else if( cpu_avail > 60 ) {
cunit = "min";
cpu_avail /= 60;
}
if ( res.total_resources.is_object() ) {
asset cpu_own( res.delegated_bandwidth.is_object() ? stoll( res.delegated_bandwidth.get_object()["cpu_weight"].as_string() ) : 0 );
auto cpu_others = to_asset(res.total_resources.get_object()["cpu_weight"].as_string()) - cpu_own;
......@@ -1204,12 +1244,12 @@ void get_account( const string& accountName, bool json_format ) {
<< std::string(11, ' ') << "(total staked delegated to account from others)" << std::endl;
}
std::cout << indent << "current:" << std::setw(15) << ("~"+std::to_string(res.cpu_limit.current_per_block/1024)) << " kcycle/block"
<< std::string(2, ' ') << "(assuming current congestion and current usage)" << std::endl
<< indent << "max:" << std::setw(19) << ("~"+std::to_string(res.cpu_limit.max_per_block/1024)) << " kcycle/block"
<< std::string(2, ' ') << "(assuming current congestion and 0 usage in current window)" << std::endl
std::cout << indent << "used:" << std::setw(15) << ("~"+std::to_string(double(res.cpu_limit.used/1000000.))) << " sec (past 3 days)\n"
<< indent << "available:" << std::setw(19) << ("~"+std::to_string(cpu_avail) )<< " " << cunit <<"\n"
/*
<< indent << "guaranteed:" << std::setw(12) << res.cpu_limit.guaranteed_per_day/1024 << " kcycle/day"
<< std::string(4, ' ') << "(assuming 100% congestion and 0 usage in current window)" << std::endl
*/
<< std::endl;
if ( res.voter_info.is_object() ) {
......
......@@ -27,18 +27,14 @@ target_link_libraries( unit_test eosio_chain chainbase eosio_testing eos_utiliti
target_include_directories( unit_test PUBLIC ${CMAKE_BINARY_DIR}/contracts ${CMAKE_CURRENT_BINARY_DIR}/tests/contracts )
target_include_directories( unit_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/wasm_tests )
target_include_directories( unit_test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include )
add_dependencies(unit_test asserter test_api test_api_mem test_api_db test_api_multi_index exchange eosio.token proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop dice eosio.msig)
add_dependencies(unit_test asserter test_api test_api_mem test_api_db test_api_multi_index exchange eosio.token proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop dice eosio.msig payloadless tic_tac_toe)
#Manually run unit_test for all supported runtimes
#To run unit_test with all log from blockchain displayed, put --verbose after --, i.e. unit_test -- --verbose
add_test(NAME unit_test_binaryen COMMAND unit_test
-t \!eosio_system_tests/*
-t \!resource_limits_test/enforce_block_limits_cpu
-t \!wasm_tests/weighted_cpu_limit_tests
--report_level=detailed --color_output -- --binaryen)
add_test(NAME unit_test_wavm COMMAND unit_test
-t \!eosio_system_tests/*
-t \!resource_limits_test/enforce_block_limits_cpu
-t \!wasm_tests/weighted_cpu_limit_tests
--report_level=detailed --color_output --catch_system_errors=no -- --wavm)
......
......@@ -25,6 +25,7 @@
#include <eosio/chain/block_summary_object.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/wasm_interface.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <fc/crypto/digest.hpp>
#include <fc/crypto/sha256.hpp>
......@@ -207,8 +208,10 @@ bool is_page_memory_error(page_memory_error const &e) { return true; }
bool is_unsatisfied_authorization(unsatisfied_authorization const & e) { return true;}
bool is_wasm_execution_error(eosio::chain::wasm_execution_error const& e) {return true;}
bool is_tx_net_usage_exceeded(const tx_net_usage_exceeded& e) { return true; }
bool is_block_net_usage_exceeded(const tx_cpu_usage_exceeded& e) { return true; }
bool is_tx_cpu_usage_exceeded(const tx_cpu_usage_exceeded& e) { return true; }
bool is_tx_deadline_exceeded(const tx_deadline_exceeded& e) { return true; }
bool is_block_cpu_usage_exceeded(const tx_cpu_usage_exceeded& e) { return true; }
bool is_deadline_exception(const deadline_exception& e) { return true; }
/*
* register test suite `api_tests`
......@@ -244,7 +247,7 @@ BOOST_FIXTURE_TEST_CASE(action_tests, TESTER) { try {
create_account( N(acc2) );
create_account( N(acc3) );
create_account( N(acc4) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
......@@ -400,7 +403,7 @@ BOOST_FIXTURE_TEST_CASE(cf_action_tests, TESTER) { try {
produce_blocks(2);
create_account( N(testapi) );
create_account( N(dummy) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
cf_action cfa;
......@@ -637,7 +640,7 @@ BOOST_FIXTURE_TEST_CASE(deferred_cfa_success, TESTER) try {
BOOST_FIXTURE_TEST_CASE(checktime_pass_tests, TESTER) { try {
produce_blocks(2);
create_account( N(testapi) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
......@@ -662,7 +665,11 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
ilog( "produce block" );
t.produce_blocks(1);
auto call_test = [](TESTER& test, auto ac) {
int64_t x; int64_t net; int64_t cpu;
t.control->get_resource_limits_manager().get_account_limits( N(testapi), x, net, cpu );
wdump((net)(cpu));
auto call_test = [](TESTER& test, auto ac, uint32_t billed_cpu_time_us, uint8_t max_cpu_usage_ms ) {
signed_transaction trx;
auto pl = vector<permission_level>{{N(testapi), config::active_name}};
......@@ -672,15 +679,26 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
trx.actions.push_back(act);
test.set_transaction_headers(trx);
trx.max_cpu_usage_ms = max_cpu_usage_ms;
auto sigs = trx.sign(test.get_private_key(N(testapi), "active"), chain_id_type());
trx.get_signature_keys(chain_id_type() );
auto res = test.push_transaction(trx);
auto res = test.push_transaction( trx, fc::time_point::now() + fc::milliseconds(200), billed_cpu_time_us );
BOOST_CHECK_EQUAL(res->receipt->status, transaction_receipt::executed);
test.produce_block();
};
BOOST_CHECK_EXCEPTION(call_test( t, test_api_action<TEST_METHOD("test_checktime", "checktime_failure")>{}), tx_deadline_exceeded, is_tx_cpu_usage_exceeded /*tx_deadline_exceeded, is_tx_deadline_exceeded*/);
BOOST_CHECK_EXCEPTION( call_test( t, test_api_action<TEST_METHOD("test_checktime", "checktime_failure")>{},
5000, 0 ),
deadline_exception, is_deadline_exception );
BOOST_CHECK_EXCEPTION( call_test( t, test_api_action<TEST_METHOD("test_checktime", "checktime_failure")>{},
0, 50 ),
tx_cpu_usage_exceeded, is_tx_cpu_usage_exceeded );
BOOST_CHECK_EXCEPTION( call_test( t, test_api_action<TEST_METHOD("test_checktime", "checktime_failure")>{},
0, 0 ),
block_cpu_usage_exceeded, is_block_cpu_usage_exceeded ); // Because the onblock uses up some of the CPU
BOOST_REQUIRE_EQUAL( t.validate(), true );
} FC_LOG_AND_RETHROW() }
......@@ -691,7 +709,7 @@ BOOST_AUTO_TEST_CASE(checktime_fail_tests) { try {
BOOST_FIXTURE_TEST_CASE(compiler_builtins_tests, TESTER) { try {
produce_blocks(2);
create_account( N(testapi) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_wast );
produce_blocks(1);
......@@ -1028,7 +1046,7 @@ BOOST_FIXTURE_TEST_CASE(db_tests, TESTER) { try {
produce_blocks(2);
create_account( N(testapi) );
create_account( N(testapi2) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_db_wast );
set_code( N(testapi2), test_api_db_wast );
produce_blocks(1);
......@@ -1171,9 +1189,9 @@ BOOST_FIXTURE_TEST_CASE(multi_index_tests, TESTER) { try {
BOOST_FIXTURE_TEST_CASE(fixedpoint_tests, TESTER) { try {
produce_blocks(2);
create_account( N(testapi) );
produce_blocks(1000);
produce_blocks(10);
set_code( N(testapi), test_api_wast );
produce_blocks(1000);
produce_blocks(10);
CALL_TEST_FUNCTION( *this, "test_fixedpoint", "create_instances", {});
CALL_TEST_FUNCTION( *this, "test_fixedpoint", "test_addition", {});
......
......@@ -253,19 +253,22 @@ BOOST_FIXTURE_TEST_CASE( bootseq_test, bootseq_tester ) {
auto net = (ib - ram) / 2;
auto cpu = ib - net - ram;
base_tester::push_action(N(eosio), N(buyram), N(eosio), mutable_variant_object()
auto r = base_tester::push_action(N(eosio), N(buyram), N(eosio), mutable_variant_object()
("payer", "eosio")
("receiver", name(a.aname))
("quant", asset(ram))
);
BOOST_REQUIRE( !r->except_ptr );
base_tester::push_action(N(eosio), N(delegatebw), N(eosio), mutable_variant_object()
r = base_tester::push_action(N(eosio), N(delegatebw), N(eosio), mutable_variant_object()
("from", "eosio" )
("receiver", name(a.aname))
("stake_net_quantity", asset(net))
("stake_cpu_quantity", asset(cpu))
("transfer", 1)
);
BOOST_REQUIRE( !r->except_ptr );
}
produce_blocks(10000);
......
此差异已折叠。
......@@ -283,7 +283,6 @@ BOOST_AUTO_TEST_CASE(confirmation) try {
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(0, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// invalid signature
BOOST_REQUIRE_EXCEPTION(c.control->push_confirmation(header_confirmation{blk->id, N(sam), priv_invalid.sign(blk->sig_digest())}),
......@@ -304,7 +303,6 @@ BOOST_AUTO_TEST_CASE(confirmation) try {
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(1, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// double confirm not allowed
BOOST_REQUIRE_EXCEPTION(c.control->push_confirmation(header_confirmation{blk->id, N(sam), priv_sam.sign(blk->sig_digest())}),
......@@ -318,7 +316,6 @@ BOOST_AUTO_TEST_CASE(confirmation) try {
BOOST_REQUIRE_EQUAL(0, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(2, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// signed by pam
c.control->push_confirmation(header_confirmation{blk->id, N(pam), priv_pam.sign(blk->sig_digest())});
......@@ -328,14 +325,12 @@ BOOST_AUTO_TEST_CASE(confirmation) try {
BOOST_REQUIRE_EQUAL(55, blk61->bft_irreversible_blocknum); // bft irreversible number will propagate to higher block
BOOST_REQUIRE_EQUAL(0, blk50->bft_irreversible_blocknum); // bft irreversible number will not propagate to lower block
BOOST_REQUIRE_EQUAL(3, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// signed by scott
c.control->push_confirmation(header_confirmation{blk->id, N(scott), priv_scott.sign(blk->sig_digest())});
BOOST_REQUIRE_EQUAL(55, blk->bft_irreversible_blocknum);
BOOST_REQUIRE_EQUAL(4, blk->confirmations.size());
printf("bft number is %d #confirms %d\n", blk->bft_irreversible_blocknum, (int)blk->confirmations.size());
// let's confirm block 50 as well
c.control->push_confirmation(header_confirmation{blk50->id, N(sam), priv_sam.sign(blk50->sig_digest())});
......
......@@ -138,6 +138,10 @@ BOOST_AUTO_TEST_SUITE(resource_limits_test)
/**
* create 5 accounts with different weights, verify that the capacities are as expected and that usage properly enforces them
*/
#warning restore weighted capacity cpu tests
#if 0
BOOST_FIXTURE_TEST_CASE(weighted_capacity_cpu, resource_limits_fixture) try {
const vector<int64_t> weights = { 234, 511, 672, 800, 1213 };
const int64_t total = std::accumulate(std::begin(weights), std::end(weights), 0LL);
......@@ -198,6 +202,7 @@ BOOST_AUTO_TEST_SUITE(resource_limits_test)
BOOST_REQUIRE_THROW(add_transaction_usage({account}, 0, expected_limits.at(idx) + 1, 0), tx_net_usage_exceeded);
}
} FC_LOG_AND_RETHROW();
#endif
BOOST_FIXTURE_TEST_CASE(enforce_block_limits_cpu, resource_limits_fixture) try {
const account_name account(1);
......@@ -206,9 +211,9 @@ BOOST_AUTO_TEST_SUITE(resource_limits_test)
process_account_limit_updates();
const uint64_t increment = 1000;
const uint64_t expected_iterations = (config::default_max_block_cpu_usage + increment - 1 ) / increment;
const uint64_t expected_iterations = config::default_max_block_cpu_usage / increment;
for (int idx = 0; idx < expected_iterations - 1; idx++) {
for (int idx = 0; idx < expected_iterations; idx++) {
add_transaction_usage({account}, increment, 0, 0);
}
......@@ -223,9 +228,9 @@ BOOST_AUTO_TEST_SUITE(resource_limits_test)
process_account_limit_updates();
const uint64_t increment = 1000;
const uint64_t expected_iterations = (config::default_max_block_net_usage + increment - 1 ) / increment;
const uint64_t expected_iterations = config::default_max_block_net_usage / increment;
for (int idx = 0; idx < expected_iterations - 1; idx++) {
for (int idx = 0; idx < expected_iterations; idx++) {
add_transaction_usage({account}, 0, increment, 0);
}
......@@ -301,4 +306,30 @@ BOOST_AUTO_TEST_SUITE(resource_limits_test)
BOOST_REQUIRE_THROW(verify_account_ram_usage(account), ram_usage_exceeded);
} FC_LOG_AND_RETHROW();
BOOST_FIXTURE_TEST_CASE(sanity_check, resource_limits_fixture) try {
double total_staked_tokens = 1'000'000'000'0000.;
double user_stake = 1'0000.;
double max_block_cpu = 100000.; // us;
double blocks_per_day = 2*60*60*23;
double total_cpu_per_period = max_block_cpu * blocks_per_day * 3;
double congested_cpu_time_per_period = total_cpu_per_period * user_stake / total_staked_tokens;
wdump((congested_cpu_time_per_period));
double uncongested_cpu_time_per_period = (1000*total_cpu_per_period) * user_stake / total_staked_tokens;
wdump((uncongested_cpu_time_per_period));
initialize_account( N(dan) );
initialize_account( N(everyone) );
set_account_limits( N(dan), 0, 0, 10000 );
set_account_limits( N(everyone), 0, 0, 10000000000000ll );
process_account_limit_updates();
add_transaction_usage( {N(dan)}, 10, 0, 1 ); /// dan should be able to do 10 us per 3 days
} FC_LOG_AND_RETHROW()
BOOST_AUTO_TEST_SUITE_END()
......@@ -616,7 +616,7 @@ BOOST_FIXTURE_TEST_CASE(weighted_cpu_limit_tests, tester ) try {
while (count < 4) {
signed_transaction trx;
for (int i = 0; i < 1000; ++i) {
for (int i = 0; i < 10; ++i) {
action act;
act.account = N(f_tests);
act.name = N() + (i * 16);
......@@ -628,12 +628,12 @@ BOOST_FIXTURE_TEST_CASE(weighted_cpu_limit_tests, tester ) try {
trx.sign(get_private_key( N(f_tests), "active" ), chain_id_type());
try {
push_transaction(trx);
push_transaction(trx, fc::time_point::maximum(), 0);
produce_blocks(1);
BOOST_REQUIRE_EQUAL(true, chain_has_transaction(trx.id()));
pass = true;
count++;
} catch (eosio::chain::tx_deadline_exceeded &) {
} catch( eosio::chain::leeway_deadline_exception& ) {
BOOST_REQUIRE_EQUAL(count, 3);
break;
}
......@@ -1481,6 +1481,9 @@ BOOST_FIXTURE_TEST_CASE( protect_injected, TESTER ) try {
produce_blocks(1);
} FC_LOG_AND_RETHROW()
#warning restore net_usage_tests
#if 0
BOOST_FIXTURE_TEST_CASE(net_usage_tests, tester ) try {
int count = 0;
auto check = [&](int coderepeat, int max_net_usage)-> bool {
......@@ -1587,5 +1590,6 @@ BOOST_FIXTURE_TEST_CASE(weighted_net_usage_tests, tester ) try {
BOOST_REQUIRE_EQUAL(false, check(128));
} FC_LOG_AND_RETHROW()
#endif
BOOST_AUTO_TEST_SUITE_END()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册