提交 d4d27e3e 编写于 作者: D Daniel Larimer

work on reintegrating resource limits manager

上级 fb5d34f4
......@@ -55,10 +55,6 @@ action_trace apply_context::exec_one()
executed.emplace_back( move(r) );
total_cpu_usage += cpu_usage;
//results.applied_actions.emplace_back(action_trace {receiver, context_free, _cpu_usage, act, _pending_console_output.str(), move(data_access)});
_pending_console_output = std::ostringstream();
t.elapsed = fc::time_point::now() - start;
......@@ -237,7 +233,7 @@ void apply_context::execute_context_free_inline( action&& a ) {
/// TODO: rename this schedule_deferred it is not actually executed here
void apply_context::execute_deferred( deferred_transaction&& trx ) {
void apply_context::schedule_deferred_transaction( deferred_transaction&& trx ) {
trx.sender = receiver;
EOS_ASSERT( trx.execute_after < trx.expiration,
transaction_exception,
......@@ -251,6 +247,28 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
require_authorization(trx.payer); /// uses payer's storage
}
}
auto id = trx.id();
auto trx_size = fc::raw::pack_size(trx);
auto& d = control.db();
d.create<generated_transaction_object>( [&]( auto& gtx ) {
gtx.trx_id = id;
gtx.sender = trx.sender;
gtx.sender_id = trx.sender_id;
gtx.payer = trx.payer;
gtx.delay_until = trx.execute_after;
gtx.expiration = trx.expiration;
gtx.published = control.pending_block_time();
gtx.packed_trx.resize( trx_size );
fc::datastream<char*> ds( gtx.packed_trx.data(), trx_size );
fc::raw::pack( ds, trx );
});
auto& rl = control.get_mutable_resource_limits_manager();
rl.add_pending_account_ram_usage( trx.payer, config::billable_size_v<generated_transaction_object> + trx_size );
checktime( trx_size * 4 ); /// 4 instructions per byte of packed generated trx (estimated)
#if 0
try {
......@@ -305,24 +323,26 @@ void apply_context::execute_deferred( deferred_transaction&& trx ) {
#endif
}
void apply_context::cancel_deferred( const uint128_t& sender_id ) {
//results.deferred_transaction_requests.push_back(deferred_reference(receiver, sender_id));
void apply_context::cancel_deferred_transaction( const uint128_t& sender_id ) {
auto& generated_transaction_idx = db.get_mutable_index<generated_transaction_multi_index>();
const auto& gto = db.get<generated_transaction_object,by_sender_id>(sender_id);
FC_ASSERT( gto.sender == receiver, "you can only cancel the transactions you send" );
control.get_mutable_resource_limits_manager().add_pending_account_ram_usage(gto.payer, -( config::billable_size_v<generated_transaction_object> + gto.packed_trx.size()));
generated_transaction_idx.remove(gto);
checktime( 100 );
}
const table_id_object* apply_context::find_table( name code, name scope, name table ) {
// require_read_lock(code, scope);
return db.find<table_id_object, by_code_scope_table>(boost::make_tuple(code, scope, table));
}
const table_id_object& apply_context::find_or_create_table( name code, name scope, name table, const account_name &payer ) {
// require_read_lock(code, scope);
const auto* existing_tid = db.find<table_id_object, by_code_scope_table>(boost::make_tuple(code, scope, table));
if (existing_tid != nullptr) {
return *existing_tid;
}
// require_write_lock(scope);
update_db_usage(payer, config::billable_size_v<table_id_object>);
return db.create<table_id_object>([&](table_id_object &t_id){
......@@ -359,20 +379,6 @@ void apply_context::checktime(uint32_t instruction_count) {
const bytes& apply_context::get_packed_transaction() {
return trx_meta.raw_packed;
/*
if( !trx_meta.packed_trx.size() ) {
if (_cached_trx.empty()) {
auto size = fc::raw::pack_size(trx_meta.trx());
_cached_trx.resize(size);
fc::datastream<char *> ds(_cached_trx.data(), size);
fc::raw::pack(ds, trx_meta.trx());
}
return _cached_trx;
}
return trx_meta.packed_trx;
*/
}
void apply_context::update_db_usage( const account_name& payer, int64_t delta ) {
......
......@@ -310,13 +310,15 @@ struct controller_impl {
}
void commit_block( bool add_to_fork_db ) {
set_pending_tapos();
resource_limits.process_account_limit_updates();
resource_limits.process_block_usage( pending->_pending_block_state->block_num );
if( add_to_fork_db ) {
pending->_pending_block_state->validated = true;
head = fork_db.add( pending->_pending_block_state );
}
set_pending_tapos();
pending->push();
pending.reset();
self.accepted_block( head );
......
......@@ -502,7 +502,7 @@ void apply_eosio_postrecovery(apply_context& context) {
dtrx.actions.emplace_back(vector<permission_level>{{account,config::active_name}},
passrecovery { account });
context.execute_deferred(std::move(dtrx));
context.schedule_deferred_transaction(std::move(dtrx));
auto data = get_abi_serializer().variant_to_binary("pending_recovery", record_data);
const uint64_t id = account;
......@@ -559,7 +559,7 @@ void apply_eosio_vetorecovery(apply_context& context) {
FC_ASSERT(maybe_recovery, "No pending recovery found for account ${account}", ("account", account));
auto recovery = *maybe_recovery;
context.cancel_deferred(recovery["request_id"].as<uint128_t>());
context.cancel_deferred_transaction(recovery["request_id"].as<uint128_t>());
remove_pending_recovery(context, account);
context.console_append_formatted("Recovery for account ${account} vetoed!\n", mutable_variant_object()("account", account));
......@@ -594,7 +594,7 @@ void apply_eosio_canceldelay(apply_context& context) {
FC_ASSERT (found, "canceldelay action must be signed with the \"active\" permission for one of the actors"
" provided in the authorizations on the original transaction");
context.cancel_deferred(transaction_id_to_sender_id(trx_id));
context.cancel_deferred_transaction(transaction_id_to_sender_id(trx_id));
}
} } // namespace eosio::chain
......@@ -470,8 +470,8 @@ class apply_context {
void execute_inline( action &&a );
void execute_context_free_inline( action &&a );
void execute_deferred( deferred_transaction &&trx );
void cancel_deferred( const uint128_t& sender_id );
void schedule_deferred_transaction( deferred_transaction &&trx );
void cancel_deferred_transaction( const uint128_t& sender_id );
/**
* @brief Require @ref account to have approved of this message
......
......@@ -40,7 +40,6 @@ namespace eosio { namespace chain { namespace resource_limits {
void add_pending_account_ram_usage( const account_name account, int64_t ram_delta );
void synchronize_account_ram_usage( );
void set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight);
void get_account_limits( const account_name& account, int64_t& ram_bytes, int64_t& net_weight, int64_t& cpu_weight) const;
......
......@@ -117,25 +117,13 @@ namespace eosio { namespace chain { namespace resource_limits {
usage_accumulator cpu_usage;
uint64_t ram_usage = 0;
uint64_t pending_ram_usage = 0;
bool is_dirty() const {
// checks for ram_usage overflowing a signed int are maintained in the update step
return ram_usage != pending_ram_usage;
}
};
using resource_usage_index = chainbase::shared_multi_index_container<
resource_usage_object,
indexed_by<
ordered_unique<tag<by_id>, member<resource_usage_object, resource_usage_object::id_type, &resource_usage_object::id>>,
ordered_unique<tag<by_owner>, member<resource_usage_object, account_name, &resource_usage_object::owner> >,
ordered_unique<tag<by_dirty>,
composite_key<resource_usage_object,
BOOST_MULTI_INDEX_CONST_MEM_FUN(resource_usage_object, bool, is_dirty),
BOOST_MULTI_INDEX_MEMBER(resource_usage_object, resource_usage_object::id_type, id)
>
>
ordered_unique<tag<by_owner>, member<resource_usage_object, account_name, &resource_usage_object::owner> >
>
>;
......
......@@ -28,6 +28,7 @@ namespace eosio { namespace chain {
controller& control;
const transaction_metadata_ptr& trx_meta;
chainbase::database::session undo_session;
flat_set<account_name> bill_to_accounts;
};
} }
......@@ -125,40 +125,28 @@ void resource_limits_manager::add_pending_account_ram_usage( const account_name
return;
}
const auto& usage = _db.get<resource_usage_object,by_owner>( account );
EOS_ASSERT(ram_delta < 0 || UINT64_MAX - usage.pending_ram_usage >= (uint64_t)ram_delta, transaction_exception, "Ram usage delta would overflow UINT64_MAX");
EOS_ASSERT(ram_delta > 0 || usage.pending_ram_usage >= (uint64_t)(-ram_delta), transaction_exception, "Ram usage delta would underflow UINT64_MAX");
const auto& limits = _db.get<resource_limits_object,by_owner>( boost::make_tuple(false, account));
const auto& usage = _db.get<resource_usage_object,by_owner>( account );
_db.modify(usage, [&](resource_usage_object& o){
o.pending_ram_usage += ram_delta;
_db.modify( usage, [&]( auto& u ) {
u.ram_usage += ram_delta;
});
}
void resource_limits_manager::synchronize_account_ram_usage( ) {
auto& multi_index = _db.get_mutable_index<resource_usage_index>();
auto& by_dirty_index = multi_index.indices().get<by_dirty>();
while(!by_dirty_index.empty()) {
const auto& itr = by_dirty_index.lower_bound(boost::make_tuple(true));
if (itr == by_dirty_index.end() || itr->is_dirty() != true) {
break;
}
FC_ASSERT( usage.ram_usage >= 0, "cannot have negative usage!" );
const auto& limits = _db.get<resource_limits_object,by_owner>( boost::make_tuple(false, itr->owner));
EOS_ASSERT(ram_delta < 0 || UINT64_MAX - usage.ram_usage>= (uint64_t)ram_delta, transaction_exception,
"Ram usage delta would overflow UINT64_MAX");
EOS_ASSERT(ram_delta > 0 || usage.ram_usage >= (uint64_t)(-ram_delta), transaction_exception,
"Ram usage delta would underflow UINT64_MAX");
if (limits.ram_bytes >= 0 && itr->pending_ram_usage > limits.ram_bytes) {
tx_resource_exhausted e(FC_LOG_MESSAGE(error, "account ${a} has insufficient ram bytes", ("a", itr->owner)));
e.append_log(FC_LOG_MESSAGE(error, "needs ${d} has ${m}", ("d",itr->pending_ram_usage)("m",limits.ram_bytes)));
throw e;
}
_db.modify(*itr, [&](resource_usage_object& o){
o.ram_usage = o.pending_ram_usage;
});
if( limits.ram_bytes >= 0 && usage.ram_usage > limits.ram_bytes ) {
tx_resource_exhausted e(FC_LOG_MESSAGE(error, "account ${a} has insufficient ram bytes", ("a", account)));
e.append_log(FC_LOG_MESSAGE(error, "needs ${d} has ${m}", ("d",usage.ram_usage)("m",limits.ram_bytes)));
throw e;
}
}
void resource_limits_manager::set_account_limits( const account_name& account, int64_t ram_bytes, int64_t net_weight, int64_t cpu_weight) {
const auto& usage = _db.get<resource_usage_object,by_owner>( account );
/*
......
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/transaction_context.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/resource_limits.hpp>
namespace eosio { namespace chain {
......@@ -27,13 +28,23 @@ namespace eosio { namespace chain {
for( const auto& act : trx_meta->trx.actions ) {
dispatch_action( act, act.account, false );
for( const auto& auth : act.authorization )
bill_to_accounts.insert( auth.actor );
}
auto& rl = control.get_mutable_resource_limits_manager();
auto net_usage = trx_meta->packed_trx.get_billable_size();
vector<account_name> bta( bill_to_accounts.begin(), bill_to_accounts.end() );
rl.add_transaction_usage( bta, trace->cpu_usage, net_usage, block_timestamp_type(control.pending_block_time()).slot );
undo_session.squash();
}
void transaction_context::dispatch_action( const action& a, account_name receiver, bool context_free ) {
apply_context acontext( control, a, *trx_meta );
acontext.context_free = context_free;
acontext.receiver = receiver;
acontext.processing_deadline = processing_deadline;
......
......@@ -1060,13 +1060,13 @@ class transaction_api : public context_aware_api {
dtrx.sender_id = sender_id;
dtrx.execute_after = time_point_sec( (context.control.head_block_time() + fc::seconds(dtrx.delay_sec)) + fc::microseconds(999'999) ); // rounds up to nearest second
dtrx.payer = payer;
context.execute_deferred(std::move(dtrx));
context.schedule_deferred_transaction(std::move(dtrx));
} FC_CAPTURE_AND_RETHROW((fc::to_hex(data, data_len)));
}
void cancel_deferred( const unsigned __int128& val ) {
fc::uint128_t sender_id(val>>64, uint64_t(val) );
context.cancel_deferred( (unsigned __int128)sender_id );
context.cancel_deferred_transaction( (unsigned __int128)sender_id );
}
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册