未验证 提交 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);
......
......@@ -3,6 +3,7 @@
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/contract_table_objects.hpp>
#include <eosio/chain/global_property_object.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio.system/eosio.system.wast.hpp>
#include <eosio.system/eosio.system.abi.hpp>
......@@ -160,19 +161,12 @@ public:
return push_transaction( trx );
}
transaction_trace_ptr setup_producer_accounts() {
std::vector<account_name> accounts;
accounts.reserve( 'z' - 'a' + 1);
std::string root( "init" );
for ( char c = 'a'; c <= 'z' ; ++c ) {
accounts.emplace_back( root + std::string(1, c) );
}
transaction_trace_ptr setup_producer_accounts( const std::vector<account_name>& accounts ) {
account_name creator(N(eosio));
signed_transaction trx;
set_transaction_headers(trx);
asset cpu = asset::from_string("1000000.0000 EOS");
asset net = asset::from_string("1000000.0000 EOS");
asset cpu = asset::from_string("80.0000 EOS");
asset net = asset::from_string("80.0000 EOS");
asset ram = asset::from_string("1.0000 EOS");
for (const auto& a: accounts) {
......@@ -198,7 +192,7 @@ public:
("receiver", a)
("stake_net_quantity", net)
("stake_cpu_quantity", cpu )
("transfer", 0 )
("transfer", 0 )
)
);
}
......@@ -289,11 +283,13 @@ public:
}
action_result regproducer( const account_name& acnt, int params_fixture = 1 ) {
return push_action( acnt, N(regproducer), mvo()
action_result r = push_action( acnt, N(regproducer), mvo()
("producer", acnt )
("producer_key", get_public_key( acnt, "active" ) )
("url", "" )
);
BOOST_REQUIRE_EQUAL( success(), r);
return r;
}
uint32_t last_block_time() const {
......@@ -331,7 +327,7 @@ public:
}
fc::variant get_producer_info( const account_name& act ) {
vector<char> data = get_row_by_account( config::system_account_name, config::system_account_name, config::producers_account_name, act );
vector<char> data = get_row_by_account( config::system_account_name, config::system_account_name, N(producers), act );
return abi_ser.binary_to_variant( "producer_info", data );
}
......@@ -412,6 +408,10 @@ fc::mutable_variant_object voter( account_name acct, const string& vote_stake )
return voter( acct )( "staked", asset::from_string( vote_stake ).amount );
}
fc::mutable_variant_object voter( account_name acct, int64_t vote_stake ) {
return voter( acct )( "staked", vote_stake );
}
fc::mutable_variant_object proxy( account_name acct ) {
return voter( acct )( "is_proxy", 1 );
}
......@@ -496,12 +496,12 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try {
produce_block( fc::hours(1) );
produce_blocks(1);
BOOST_REQUIRE_EQUAL( asset::from_string("1000.0000 EOS"), get_balance( "alice" ) );
BOOST_REQUIRE_EQUAL( success(), stake( "alice", "bob", "200.0000 EOS", "100.0000 EOS" ) );
BOOST_REQUIRE_EQUAL( asset::from_string("700.0000 EOS"), get_balance( "alice" ) );
BOOST_REQUIRE_EQUAL( success(), buyram( "alice", "bob", "200.0000 EOS" ) );
BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 100 ) );
BOOST_REQUIRE_EQUAL( success(), sellram( "bob", 100 ) );
BOOST_REQUIRE_EQUAL( success(), buyrambytes( "alice", "bob", 10000 ) );
total = get_total_stake("bob");
BOOST_REQUIRE_EQUAL( asset::from_string("210.0000 EOS"), total["net_weight"].as<asset>());
BOOST_REQUIRE_EQUAL( asset::from_string("110.0000 EOS"), total["cpu_weight"].as<asset>());
total = get_total_stake( "alice" );
BOOST_REQUIRE_EQUAL( asset::from_string("210.0000 EOS").amount, total["net_weight"].as<asset>().amount );
......@@ -512,28 +512,21 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, eosio_system_tester ) try {
auto bytes = total["ram_bytes"].as_uint64();
BOOST_REQUIRE_EQUAL( true, 0 < bytes );
BOOST_REQUIRE_EQUAL( asset::from_string("200.0000 EOS"), get_balance( "alice" ) );
//unstake
BOOST_REQUIRE_EQUAL( success(), unstake( "alice", "200.0000 EOS", "100.0000 EOS" ) );
total = get_total_stake( "alice" );
BOOST_REQUIRE_EQUAL( asset::from_string("10.0000 EOS").amount, total["net_weight"].as<asset>().amount);
BOOST_REQUIRE_EQUAL( asset::from_string("10.0000 EOS").amount, total["cpu_weight"].as<asset>().amount);
REQUIRE_MATCHING_OBJECT( voter( "alice", "0.0000 EOS" ), get_voter_info( "alice" ) );
produce_blocks(1);
BOOST_REQUIRE_EQUAL( asset::from_string("200.0000 EOS"), get_balance( "alice" ) );
//after 2 days balance should not be available yet
//unstake from bob
BOOST_REQUIRE_EQUAL( success(), unstake( "alice", "bob", "200.0000 EOS", "100.0000 EOS" ) );
total = get_total_stake("bob");
BOOST_REQUIRE_EQUAL( asset::from_string("10.0000 EOS"), total["net_weight"].as<asset>());
BOOST_REQUIRE_EQUAL( asset::from_string("10.0000 EOS"), total["cpu_weight"].as<asset>());
produce_block( fc::hours(3*24-1) );
produce_blocks(1);
BOOST_REQUIRE_EQUAL( asset::from_string("200.0000 EOS"), get_balance( "alice" ) );
BOOST_REQUIRE_EQUAL( asset::from_string("700.0000 EOS"), get_balance( "alice" ) );
//after 3 days funds should be released
produce_block( fc::hours(1) );
produce_blocks(1);
BOOST_REQUIRE_EQUAL( asset::from_string("1000.0000 EOS"), get_balance( "alice" ) );
REQUIRE_MATCHING_OBJECT( voter( "alice", "0.0000 EOS" ), get_voter_info( "alice" ) );
produce_blocks(1);
BOOST_REQUIRE_EQUAL( asset::from_string("1000.0000 EOS"), get_balance( "alice" ) );
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( fail_without_auth, eosio_system_tester ) try {
......@@ -1180,7 +1173,7 @@ BOOST_FIXTURE_TEST_CASE( proxy_register_unregister_keeps_stake, eosio_system_tes
issue( "carol", "1000.0000 EOS", config::system_account_name );
BOOST_REQUIRE_EQUAL( success(), stake( "carol", "246.0002 EOS", "531.0001 EOS" ) );
//check that both proxy flag and stake a correct
REQUIRE_MATCHING_OBJECT( proxy( "carol" )( "staked", "777.0003 EOS" ), get_voter_info( "carol" ) );
REQUIRE_MATCHING_OBJECT( proxy( "carol" )( "staked", 7770003 ), get_voter_info( "carol" ) );
//unregister
BOOST_REQUIRE_EQUAL( success(), push_action( N(carol), N(regproxy), mvo()
......@@ -1305,8 +1298,8 @@ BOOST_FIXTURE_TEST_CASE( proxy_actions_affect_producers, eosio_system_tester, *
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try {
const asset large_asset = asset::from_string("100000000.0000 EOS");
BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try {
const asset large_asset = asset::from_string("80.0000 EOS");
create_account_with_resources( N(inita), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
create_account_with_resources( N(initb), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
......@@ -1448,44 +1441,60 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, eosio_system_tester) try {
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
const auto tol = boost::test_tools::tolerance(0.0000000001);
BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester, * boost::unit_test::tolerance(1e-10)) try {
const int64_t secs_per_year = 52 * 7 * 24 * 3600;
const int64_t blocks_per_year = 52 * 7* 24 * 3600 * 2;
const int64_t secs_per_year = 52 * 7 * 24 * 3600;
const int64_t blocks_per_year = 52 * 7 * 24 * 3600 * 2;
const double cont_rate = 4.879/100.;
const double standby_rate = 0.750/100.;
const double block_rate = 0.250/100.;
const asset large_asset = asset::from_string("100000000.0000 EOS");
create_account_with_resources( N(vota), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
create_account_with_resources( N(votb), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
create_account_with_resources( N(votc), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
const asset net = asset::from_string("80.0000 EOS");
const asset cpu = asset::from_string("80.0000 EOS");
create_account_with_resources( N(vota), N(eosio), asset::from_string("1.0000 EOS"), false, net, cpu );
create_account_with_resources( N(votb), N(eosio), asset::from_string("1.0000 EOS"), false, net, cpu );
create_account_with_resources( N(votc), N(eosio), asset::from_string("1.0000 EOS"), false, net, cpu );
// create accounts {inita, initb, ..., initz} and register as producers
setup_producer_accounts();
std::vector<account_name> producer_names;
{
producer_names.reserve( 'z' - 'a' + 1);
const std::string root( "init" );
for ( char c = 'a'; c <= 'z' ; ++c ) {
producer_names.reserve('z' - 'a' + 1);
const std::string root("init");
for ( char c = 'a'; c <= 'z'; ++c ) {
producer_names.emplace_back(root + std::string(1, c));
regproducer( producer_names.back() );
}
BOOST_REQUIRE_EQUAL(0, get_producer_info( N(inita) )["total_votes"].as<double>());
BOOST_REQUIRE_EQUAL(0, get_producer_info( N(initz) )["total_votes"].as<double>());
setup_producer_accounts(producer_names);
for (const auto& p: producer_names) {
BOOST_REQUIRE_EQUAL( success(), regproducer(p) );
produce_blocks(10);
ilog( "------ get pro----------" );
wdump((p));
BOOST_TEST(0 == get_producer_info(p)["total_votes"].as<double>());
}
{
ilog( "------ get initz ----------" );
auto inita_info = get_producer_info( N(inita) );
wdump((inita_info));
BOOST_REQUIRE_EQUAL(0, inita_info["total_votes"].as<double>());
ilog( "------ get initz ----------" );
auto initz_info = get_producer_info( N(initz) );
wdump((initz_info));
BOOST_REQUIRE_EQUAL(0, initz_info["total_votes"].as<double>());
}
}
{
issue( "vota", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("vota", "30000000.0000 EOS", "30000000.0000 EOS"));
issue( "votb", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votb", "30000000.0000 EOS", "30000000.0000 EOS"));
issue( "votc", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votc", "30000000.0000 EOS", "30000000.0000 EOS"));
transfer( config::system_account_name, "vota", "100000000.0000 EOS", config::system_account_name );
BOOST_REQUIRE_EQUAL(success(), stake("vota", "30000000.0000 EOS", "30000000.0000 EOS") );
transfer( config::system_account_name, "votb", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votb", "30000000.0000 EOS", "30000000.0000 EOS") );
transfer( config::system_account_name, "votc", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votc", "30000000.0000 EOS", "30000000.0000 EOS") );
}
// vota votes for inita ... initj
......@@ -1505,13 +1514,14 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
("producers", vector<account_name>(producer_names.begin(), producer_names.begin()+21))
)
);
BOOST_REQUIRE_EQUAL(success(), push_action(N(votc), N(voteproducer), mvo()
("voter", "votc")
("proxy", name(0).to_string())
("producers", vector<account_name>(producer_names.begin(), producer_names.end()))
)
);
}
{
......@@ -1527,20 +1537,20 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
// check vote ratios
BOOST_REQUIRE ( 0 < proda["total_votes"].as<double>() && 0 < prodz["total_votes"].as<double>() );
BOOST_TEST( proda["total_votes"].as<double>() == prodj["total_votes"].as<double>(), tol );
BOOST_TEST( prodk["total_votes"].as<double>() == produ["total_votes"].as<double>(), tol );
BOOST_TEST( prodv["total_votes"].as<double>() == prodz["total_votes"].as<double>(), tol );
BOOST_TEST( 2 * proda["total_votes"].as<double>() == 3 * produ["total_votes"].as<double>(), tol );
BOOST_TEST( proda["total_votes"].as<double>() == 3 * prodz["total_votes"].as<double>(), tol );
BOOST_TEST( proda["total_votes"].as<double>() == prodj["total_votes"].as<double>() );
BOOST_TEST( prodk["total_votes"].as<double>() == produ["total_votes"].as<double>() );
BOOST_TEST( prodv["total_votes"].as<double>() == prodz["total_votes"].as<double>() );
BOOST_TEST( 2 * proda["total_votes"].as<double>() == 3 * produ["total_votes"].as<double>() );
BOOST_TEST( proda["total_votes"].as<double>() == 3 * prodz["total_votes"].as<double>() );
}
// give a chance for everyone to produce blocks
{
produce_blocks(21 * 12 + 20);
bool all_21_produced = true;
for (uint32_t i = 0; i < 21; ++i) {
if (0 == get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
all_21_produced= false;
all_21_produced = false;
}
}
bool rest_didnt_produce = true;
......@@ -1561,8 +1571,9 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
}
std::for_each(vote_shares.begin(), vote_shares.end(), [total_votes](double& x) { x /= total_votes; });
BOOST_TEST(double(1) == std::accumulate(vote_shares.begin(), vote_shares.end(), double(0)), tol);
BOOST_TEST(double(3./57.) == vote_shares[0], tol);
BOOST_TEST(double(1) == std::accumulate(vote_shares.begin(), vote_shares.end(), double(0)));
BOOST_TEST(double(3./57.) == vote_shares.front());
BOOST_TEST(double(1./57.) == vote_shares.back());
}
{
......@@ -1570,7 +1581,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
const auto prod_name = producer_names[prod_index];
const auto produced_blocks = get_producer_info(prod_name)["produced_blocks"].as<uint32_t>();
const auto initial_global_state = get_global_state();
const auto initial_global_state = get_global_state();
const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64();
const asset initial_pervote_bucket = initial_global_state["pervote_bucket"].as<asset>();
const asset initial_savings = initial_global_state["savings"].as<asset>();
......@@ -1623,7 +1634,10 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
push_action(prod_name, N(claimrewards), mvo()("owner", prod_name)));
}
produce_block(fc::seconds(24 * 3600));
// wait to 23 hours which is not enough for producers to get deactivated
// payment calculations don't change. By now, pervote_bucket has grown enough
// that a producer's share is more than 100 tokens
produce_block(fc::seconds(23 * 3600));
{
const uint32_t prod_index = 15;
......@@ -1665,7 +1679,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
}
{
const uint32_t prod_index = 23;
const uint32_t prod_index = 24;
const auto prod_name = producer_names[prod_index];
BOOST_REQUIRE_EQUAL(success(),
push_action(prod_name, N(claimrewards), mvo()("owner", prod_name)));
......@@ -1674,6 +1688,131 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, eosio_system_tester) try {
push_action(prod_name, N(claimrewards), mvo()("owner", prod_name)));
}
// wait two more hours, now most producers haven't produced in a day and will
// be deactivated
produce_block(fc::seconds(2 * 3600));
produce_blocks(8 * 21 * 12);
{
bool all_newly_elected_produced = true;
for (uint32_t i = 21; i < producer_names.size(); ++i) {
if (0 == get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
all_newly_elected_produced = false;
}
}
BOOST_REQUIRE(all_newly_elected_produced);
}
{
uint32_t survived_active_producers = 0;
uint32_t one_inactive_index = 0;
for (uint32_t i = 0; i < 21; ++i) {
if (fc::crypto::public_key() != fc::crypto::public_key(get_producer_info(producer_names[i])["producer_key"].as_string())) {
++survived_active_producers;
} else {
one_inactive_index = i;
}
}
BOOST_REQUIRE(3 >= survived_active_producers);
auto inactive_prod_info = get_producer_info(producer_names[one_inactive_index]);
BOOST_REQUIRE_EQUAL(0, inactive_prod_info["time_became_active"].as<uint32_t>());
BOOST_REQUIRE_EQUAL(error("condition: assertion failed: producer does not have an active key"),
push_action(producer_names[one_inactive_index], N(claimrewards), mvo()("owner", producer_names[one_inactive_index])));
}
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE(producer_onblock_check, eosio_system_tester) try {
const auto tol = boost::test_tools::tolerance(0.0000000001);
const asset large_asset = asset::from_string("100000000.0000 EOS");
create_account_with_resources( N(vota), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
create_account_with_resources( N(votb), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
create_account_with_resources( N(votc), N(eosio), asset::from_string("1.0000 EOS"), false, large_asset, large_asset );
// create accounts {inita, initb, ..., initz} and register as producers
std::vector<account_name> producer_names={N(inita),N(initb),N(initc),N(initd),N(inite),N(initf),N(initg),N(inith),
N(initi),N(initj),N(initk),N(initl),N(initm),N(initn),N(inito),N(initp),N(initq),N(initr),N(inits),N(initt),
N(initu),N(initv),N(initw),N(initx),N(inity),N(initz)};
setup_producer_accounts(producer_names);
for (auto a:producer_names)
regproducer(a);
BOOST_REQUIRE_EQUAL(0, get_producer_info( N(inita) )["total_votes"].as<double>());
BOOST_REQUIRE_EQUAL(0, get_producer_info( N(initz) )["total_votes"].as<double>());
issue( "vota", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("vota", "30000000.0000 EOS", "30000000.0000 EOS"));
BOOST_REQUIRE_EQUAL(success(), push_action(N(vota), N(voteproducer), mvo()
("voter", "vota")
("proxy", name(0).to_string())
("producers", vector<account_name>(producer_names.begin(), producer_names.begin()+10))
));
// give a chance for everyone to produce blocks
{
produce_blocks(21 * 12);
bool all_21_produced = true;
for (uint32_t i = 0; i < 21; ++i) {
if (0 == get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
all_21_produced= false;
}
}
bool rest_didnt_produce = true;
for (uint32_t i = 21; i < producer_names.size(); ++i) {
if (0 < get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
rest_didnt_produce = false;
}
}
BOOST_REQUIRE_EQUAL(false, all_21_produced);
BOOST_REQUIRE_EQUAL(true, rest_didnt_produce);
}
// issue across 15% boundary
issue( "votb", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votb", "30000000.0000 EOS", "30000000.0000 EOS"));
issue( "votc", "100000000.0000 EOS", config::system_account_name);
BOOST_REQUIRE_EQUAL(success(), stake("votc", "30000000.0000 EOS", "30000000.0000 EOS"));
BOOST_REQUIRE_EQUAL(success(), push_action(N(votb), N(voteproducer), mvo()
("voter", "votb")
("proxy", name(0).to_string())
("producers", vector<account_name>(producer_names.begin(), producer_names.begin()+21))
)
);
BOOST_REQUIRE_EQUAL(success(), push_action(N(votc), N(voteproducer), mvo()
("voter", "votc")
("proxy", name(0).to_string())
("producers", vector<account_name>(producer_names.begin(), producer_names.end()))
)
);
// give a chance for everyone to produce blocks
{
produce_blocks(21 * 12);
bool all_21_produced = true;
for (uint32_t i = 0; i < 21; ++i) {
if (0 == get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
all_21_produced= false;
}
}
bool rest_didnt_produce = true;
for (uint32_t i = 21; i < producer_names.size(); ++i) {
if (0 < get_producer_info(producer_names[i])["produced_blocks"].as<uint32_t>()) {
rest_didnt_produce = false;
}
}
BOOST_REQUIRE_EQUAL(true, all_21_produced);
BOOST_REQUIRE_EQUAL(true, rest_didnt_produce);
}
} FC_LOG_AND_RETHROW()
BOOST_FIXTURE_TEST_CASE( voters_actions_affect_proxy_and_producers, eosio_system_tester, * boost::unit_test::tolerance(1e+6) ) try {
......@@ -1854,33 +1993,33 @@ BOOST_FIXTURE_TEST_CASE( double_register_unregister_proxy_keeps_votes, eosio_sys
("producers", vector<account_name>() )
)
);
REQUIRE_MATCHING_OBJECT( proxy( "alice" )( "proxied_votes", 1500003 )( "staked", 100000 ), get_voter_info( "alice" ) );
REQUIRE_MATCHING_OBJECT( proxy( "alice" )( "proxied_vote_weight", stake2votes( "150.0003 EOS" ))( "staked", 100000 ), get_voter_info( "alice" ) );
//double regestering should fail without affecting total votes and stake
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: account is already a proxy" ),
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: action has no effect" ),
push_action( N(alice), N(regproxy), mvo()
("proxy", "alice")
("isproxy", 1)
)
);
REQUIRE_MATCHING_OBJECT( proxy( "alice" )( "proxied_votes", 1500003 )( "staked", 100000 ), get_voter_info( "alice" ) );
REQUIRE_MATCHING_OBJECT( proxy( "alice" )( "proxied_vote_weight", stake2votes("150.0003 EOS") )( "staked", 100000 ), get_voter_info( "alice" ) );
//uregister
BOOST_REQUIRE_EQUAL( success(), push_action( N(alice), N(unregproxy), mvo()
BOOST_REQUIRE_EQUAL( success(), push_action( N(alice), N(regproxy), mvo()
("proxy", "alice")
("isproxy", 0)
)
);
REQUIRE_MATCHING_OBJECT( voter( "alice" )( "proxied_votes", 1500003 )( "staked", 100000 ), get_voter_info( "alice" ) );
REQUIRE_MATCHING_OBJECT( voter( "alice" )( "proxied_vote_weight", stake2votes("150.0003 EOS") )( "staked", 100000 ), get_voter_info( "alice" ) );
//double unregistering should not affect proxied_votes and stake
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: account is not a proxy" ),
push_action( N(alice), N(unregproxy), mvo()
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: action has no effect" ),
push_action( N(alice), N(regproxy), mvo()
("proxy", "alice")
("isproxy", 0)
)
);
REQUIRE_MATCHING_OBJECT( voter( "alice" )( "proxied_votes", 1500003 )( "staked", 100000 ), get_voter_info( "alice" ) );
REQUIRE_MATCHING_OBJECT( voter( "alice" )( "proxied_vote_weight", stake2votes("150.0003 EOS"))( "staked", 100000 ), get_voter_info( "alice" ) );
} FC_LOG_AND_RETHROW()
......@@ -1927,7 +2066,7 @@ BOOST_FIXTURE_TEST_CASE( proxy_cannot_use_another_proxy, eosio_system_tester ) t
);
//proxy should not be able to use itself as a proxy
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: account registered as a proxy is not allowed to use a proxy" ),
BOOST_REQUIRE_EQUAL( error( "condition: assertion failed: cannot proxy to self" ),
push_action( N(bob), N(voteproducer), mvo()
("voter", "bob")
("proxy", "bob" )
......@@ -1963,14 +2102,16 @@ fc::mutable_variant_object config_to_variant( const eosio::chain::chain_config&
( "max_generated_transaction_count", config.max_generated_transaction_count );
}
BOOST_FIXTURE_TEST_CASE( elect_producers_and_parameters, eosio_system_tester ) try {
BOOST_FIXTURE_TEST_CASE( elect_producers /*_and_parameters*/, eosio_system_tester ) try {
create_accounts_with_resources( { N(producer1), N(producer2), N(producer3) } );
BOOST_REQUIRE_EQUAL( success(), regproducer( "producer1", 1) );
BOOST_REQUIRE_EQUAL( success(), regproducer( "producer2", 2) );
BOOST_REQUIRE_EQUAL( success(), regproducer( "producer3", 3) );
issue( "alice", "1000.0000 EOS", config::system_account_name );
BOOST_REQUIRE_EQUAL( success(), stake( "alice", "100.0000 EOS", "50.0000 EOS" ) );
//stake more than 15% of total EOS supply to activate chain
transfer( "eosio", "alice", "600000000.0000 EOS", "eosio" );
BOOST_REQUIRE_EQUAL( success(), stake( "alice", "alice", "300000000.0000 EOS", "300000000.0000 EOS" ) );
// 1000000000.0000
//vote for producers
BOOST_REQUIRE_EQUAL( success(), push_action(N(alice), N(voteproducer), mvo()
("voter", "alice")
......@@ -1978,32 +2119,35 @@ BOOST_FIXTURE_TEST_CASE( elect_producers_and_parameters, eosio_system_tester ) t
("producers", vector<account_name>{ N(producer1) } )
)
);
produce_blocks(50);
produce_blocks(250);
auto producer_keys = control->head_block_state()->active_schedule.producers;
BOOST_REQUIRE_EQUAL( 1, producer_keys.size() );
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[0].producer_name );
auto config = config_to_variant( control->get_global_properties().configuration );
auto prod1_config = testing::filter_fields( config, producer_parameters_example( 1 ) );
REQUIRE_EQUAL_OBJECTS(prod1_config, config);
//auto config = config_to_variant( control->get_global_properties().configuration );
//auto prod1_config = testing::filter_fields( config, producer_parameters_example( 1 ) );
//REQUIRE_EQUAL_OBJECTS(prod1_config, config);
// elect 2 producers
issue( "bob", "1000.0000 EOS", config::system_account_name );
BOOST_REQUIRE_EQUAL( success(), stake( "bob", "200.0000 EOS", "100.0000 EOS" ) );
issue( "bob", "80000.0000 EOS", config::system_account_name );
ilog("stake");
BOOST_REQUIRE_EQUAL( success(), stake( "bob", "40000.0000 EOS", "40000.0000 EOS" ) );
ilog("start vote");
BOOST_REQUIRE_EQUAL( success(), push_action(N(bob), N(voteproducer), mvo()
("voter", "bob")
("proxy", name(0).to_string() )
("producers", vector<account_name>{ N(producer2) } )
)
);
produce_blocks(50);
ilog(".");
produce_blocks(250);
producer_keys = control->head_block_state()->active_schedule.producers;
BOOST_REQUIRE_EQUAL( 2, producer_keys.size() );
BOOST_REQUIRE_EQUAL( name("producer2"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[1].producer_name );
config = config_to_variant( control->get_global_properties().configuration );
auto prod2_config = testing::filter_fields( config, producer_parameters_example( 2 ) );
REQUIRE_EQUAL_OBJECTS(prod2_config, config);
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer2"), producer_keys[1].producer_name );
//config = config_to_variant( control->get_global_properties().configuration );
//auto prod2_config = testing::filter_fields( config, producer_parameters_example( 2 ) );
//REQUIRE_EQUAL_OBJECTS(prod2_config, config);
// elect 3 producers
BOOST_REQUIRE_EQUAL( success(), push_action(N(bob), N(voteproducer), mvo()
......@@ -2012,14 +2156,14 @@ BOOST_FIXTURE_TEST_CASE( elect_producers_and_parameters, eosio_system_tester ) t
("producers", vector<account_name>{ N(producer2), N(producer3) } )
)
);
produce_blocks(50);
produce_blocks(250);
producer_keys = control->head_block_state()->active_schedule.producers;
BOOST_REQUIRE_EQUAL( 3, producer_keys.size() );
BOOST_REQUIRE_EQUAL( name("producer3"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer2"), producer_keys[1].producer_name );
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[2].producer_name );
config = config_to_variant( control->get_global_properties().configuration );
REQUIRE_EQUAL_OBJECTS(prod2_config, config);
BOOST_REQUIRE_EQUAL( name("producer3"), producer_keys[2].producer_name );
//config = config_to_variant( control->get_global_properties().configuration );
//REQUIRE_EQUAL_OBJECTS(prod2_config, config);
//back to 2 producers
BOOST_REQUIRE_EQUAL( success(), push_action(N(bob), N(voteproducer), mvo()
......@@ -2028,14 +2172,14 @@ BOOST_FIXTURE_TEST_CASE( elect_producers_and_parameters, eosio_system_tester ) t
("producers", vector<account_name>{ N(producer3) } )
)
);
produce_blocks(100);
produce_blocks(250);
producer_keys = control->head_block_state()->active_schedule.producers;
BOOST_REQUIRE_EQUAL( 2, producer_keys.size() );
BOOST_REQUIRE_EQUAL( name("producer3"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[1].producer_name );
config = config_to_variant( control->get_global_properties().configuration );
auto prod3_config = testing::filter_fields( config, producer_parameters_example( 3 ) );
REQUIRE_EQUAL_OBJECTS(prod3_config, config);
BOOST_REQUIRE_EQUAL( name("producer1"), producer_keys[0].producer_name );
BOOST_REQUIRE_EQUAL( name("producer3"), producer_keys[1].producer_name );
//config = config_to_variant( control->get_global_properties().configuration );
//auto prod3_config = testing::filter_fields( config, producer_parameters_example( 3 ) );
//REQUIRE_EQUAL_OBJECTS(prod3_config, config);
} FC_LOG_AND_RETHROW()
......
......@@ -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.
先完成此消息的编辑!
想要评论请 注册