11#pragma push_macro("N")
13#include <boost/accumulators/accumulators.hpp>
14#include <boost/accumulators/statistics/stats.hpp>
15#include <boost/accumulators/statistics/min.hpp>
16#include <boost/accumulators/statistics/max.hpp>
17#include <boost/accumulators/statistics/weighted_mean.hpp>
18#include <boost/accumulators/statistics/weighted_variance.hpp>
23namespace sysio {
namespace chain {
26 : expired(timer.expired),
_timer(timer) {
57 ,transaction_timer(
std::move(tmr))
59 ,net_usage(trace->net_usage)
63 undo_session.emplace(c.mutable_db().start_undo_session(true));
72 dm_logger->on_start_transaction();
80 dm_logger->on_end_transaction();
84 void transaction_context::disallow_transaction_extensions(
const char* error_msg )
const {
86 SYS_THROW( subjective_block_production_exception, error_msg );
88 SYS_THROW( disallowed_transaction_extensions_bad_block_exception, error_msg );
92 void transaction_context::init(
uint64_t initial_net_usage)
102 net_limit = rl.get_block_net_limit();
105 _deadline =
start + objective_duration_limit;
112 if( cfg.max_transaction_net_usage > 0 && cfg.max_transaction_net_usage <= net_limit ) {
113 net_limit = cfg.max_transaction_net_usage;
114 net_limit_due_to_block =
false;
123 if( cfg.max_transaction_cpu_usage > 0 && cfg.max_transaction_cpu_usage <= objective_duration_limit.count() ) {
125 billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
126 _deadline =
start + objective_duration_limit;
130 if( net_limit == 0 ) {
131 net_limit = cfg.max_block_net_usage;
133 if( objective_duration_limit.count() == 0 ) {
137 eager_net_limit = net_limit;
141 uint64_t trx_specified_net_usage_limit =
static_cast<uint64_t>(trx.max_net_usage_words.value) * 8;
142 if( trx_specified_net_usage_limit > 0 && trx_specified_net_usage_limit <= net_limit ) {
143 net_limit = trx_specified_net_usage_limit;
144 net_limit_due_to_block =
false;
148 if( trx.max_cpu_usage_ms > 0 ) {
149 auto trx_specified_cpu_usage_limit =
fc::milliseconds(trx.max_cpu_usage_ms);
150 if( trx_specified_cpu_usage_limit <= objective_duration_limit ) {
151 objective_duration_limit = trx_specified_cpu_usage_limit;
152 billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
153 _deadline =
start + objective_duration_limit;
157 initial_objective_duration_limit = objective_duration_limit;
202 _deadline =
start + max_transaction_time_subjective;
203 billing_timer_exception_code = tx_cpu_usage_exceeded::code_value;
209 billing_timer_exception_code = deadline_exception::code_value;
215 deadline_exception_code = deadline_exception::code_value;
217 deadline_exception_code = billing_timer_exception_code;
229 eager_net_limit = (eager_net_limit/8)*8;
231 if( initial_net_usage > 0 )
241 is_initialized =
true;
248 disallow_transaction_extensions(
"no transaction extensions supported yet for implicit transactions" );
252 init( initial_net_usage);
260 disallow_transaction_extensions(
"no transaction extensions supported yet for input transactions" );
265 uint64_t discounted_size_for_pruned_data = packed_trx_prunable_size;
266 if( cfg.context_free_discount_net_usage_den > 0
267 && cfg.context_free_discount_net_usage_num < cfg.context_free_discount_net_usage_den )
269 discounted_size_for_pruned_data *= cfg.context_free_discount_net_usage_num;
270 discounted_size_for_pruned_data = ( discounted_size_for_pruned_data + cfg.context_free_discount_net_usage_den - 1)
271 / cfg.context_free_discount_net_usage_den;
274 uint64_t initial_net_usage =
static_cast<uint64_t>(cfg.base_per_transaction_net_usage)
275 + packed_trx_unprunable_size + discounted_size_for_pruned_data;
281 initial_net_usage +=
static_cast<uint64_t>(cfg.base_per_transaction_net_usage)
282 +
static_cast<uint64_t>(config::transaction_id_net_usage);
292 init( initial_net_usage);
300 disallow_transaction_extensions(
"no transaction extensions supported yet for deferred transactions" );
308 trace->scheduled =
true;
319 schedule_action( act, act.account,
true, 0, 0 );
324 for(
const auto& act : trx.
actions ) {
325 schedule_action( act, act.account,
false, 0, 0 );
329 auto& action_traces =
trace->action_traces;
330 uint32_t num_original_actions_to_execute = action_traces.size();
331 for(
uint32_t i = 1; i <= num_original_actions_to_execute; ++i ) {
332 execute_action( i, 0 );
336 schedule_transaction();
346 for(
const auto& act : trx.
actions ) {
347 for(
const auto& auth : act.authorization ) {
348 am.update_permission_usage( am.get_permission(auth) );
380 net_usage = ((net_usage + 7)/8)*8;
382 eager_net_limit = net_limit;
406 if( BOOST_UNLIKELY(net_usage > eager_net_limit) ) {
407 if ( net_limit_due_to_block ) {
409 "not enough space left in block: ${net_usage} > ${net_limit}",
410 (
"net_usage", net_usage)(
"net_limit", eager_net_limit) );
411 }
else if (net_limit_due_to_greylist) {
413 "greylisted transaction net usage is too high: ${net_usage} > ${net_limit}",
414 (
"net_usage", net_usage)(
"net_limit", eager_net_limit) );
417 "transaction net usage is too high: ${net_usage} > ${net_limit}",
418 (
"net_usage", net_usage)(
"net_limit", eager_net_limit) );
430 SYS_THROW( deadline_exception,
"deadline exceeded ${billing_timer}us",
431 (
"billing_timer", now - pseudo_start)(
"now", now)(
"deadline", _deadline)(
"start",
start) );
432 }
else if( deadline_exception_code == block_cpu_usage_exceeded::code_value ) {
434 "not enough time left in block to complete executing transaction ${billing_timer}us",
435 (
"now", now)(
"deadline", _deadline)(
"start",
start)(
"billing_timer", now - pseudo_start) );
436 }
else if( deadline_exception_code == tx_cpu_usage_exceeded::code_value ) {
437 if (cpu_limit_due_to_greylist) {
439 "greylisted transaction was executing for too long ${billing_timer}us",
440 (
"now", now)(
"deadline", _deadline)(
"start",
start)(
"billing_timer", now - pseudo_start) );
443 "transaction was executing for too long ${billing_timer}us",
444 (
"now", now)(
"deadline", _deadline)(
"start",
start)(
"billing_timer", now - pseudo_start) );
446 }
else if( deadline_exception_code == leeway_deadline_exception::code_value ) {
448 "the transaction was unable to complete by deadline, "
449 "but it is possible it could have succeeded if it were allowed to run to completion ${billing_timer}",
450 (
"now", now)(
"deadline", _deadline)(
"start",
start)(
"billing_timer", now - pseudo_start) );
459 billed_time = paused_time - pseudo_start;
468 auto paused = now - paused_time;
470 pseudo_start = now - billed_time;
475 deadline_exception_code = deadline_exception::code_value;
482 void transaction_context::validate_cpu_usage_to_bill(
int64_t billed_us,
int64_t account_cpu_limit,
bool check_minimum )
const {
484 if( check_minimum ) {
487 "cannot bill CPU time less than the minimum of ${min_billable} us",
488 (
"min_billable", cfg.min_transaction_cpu_usage)(
"billed_cpu_time_us", billed_us)
492 validate_account_cpu_usage( billed_us, account_cpu_limit );
496 void transaction_context::validate_account_cpu_usage(
int64_t billed_us,
int64_t account_cpu_limit )
const {
498 const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
500 if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) {
501 SYS_ASSERT( billed_us <= objective_duration_limit.count(),
502 block_cpu_usage_exceeded,
503 "billed CPU time (${billed} us) is greater than the billable CPU time left in the block (${billable} us)",
504 (
"billed", billed_us)(
"billable", objective_duration_limit.count() )
507 if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
509 greylist_cpu_usage_exceeded,
510 "billed CPU time (${billed} us) is greater than the maximum greylisted billable CPU time for the transaction (${billable} us)",
511 (
"billed", billed_us)(
"billable", account_cpu_limit )
515 const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
517 tx_cpu_usage_exceeded,
518 "billed CPU time (${billed} us) is greater than the maximum billable CPU time for the transaction (${billable} us)",
519 (
"billed", billed_us)(
"billable", cpu_limit )
526 void transaction_context::validate_account_cpu_usage_estimate(
int64_t prev_billed_us,
int64_t account_cpu_limit )
const {
529 const bool cpu_limited_by_account = (account_cpu_limit <= objective_duration_limit.count());
531 if( !cpu_limited_by_account && (billing_timer_exception_code == block_cpu_usage_exceeded::code_value) ) {
532 SYS_ASSERT( prev_billed_us < objective_duration_limit.count(),
533 block_cpu_usage_exceeded,
534 "estimated CPU time (${billed} us) is not less than the billable CPU time left in the block (${billable} us)",
535 (
"billed", prev_billed_us)(
"billable", objective_duration_limit.count() )
538 if( cpu_limit_due_to_greylist && cpu_limited_by_account ) {
539 SYS_ASSERT( prev_billed_us < account_cpu_limit,
540 greylist_cpu_usage_exceeded,
541 "estimated CPU time (${billed} us) is not less than the maximum greylisted billable CPU time for the transaction (${billable} us)",
542 (
"billed", prev_billed_us)(
"billable", account_cpu_limit )
546 const int64_t cpu_limit = (cpu_limited_by_account ? account_cpu_limit : objective_duration_limit.count());
548 tx_cpu_usage_exceeded,
549 "estimated CPU time (${billed} us) is not less than the maximum billable CPU time for the transaction (${billable} us)",
550 (
"billed", prev_billed_us)(
"billable", cpu_limit )
560 if( ram_delta > 0 ) {
579 const static int64_t large_number_no_overflow = std::numeric_limits<int64_t>::max()/2;
580 int64_t account_net_limit = large_number_no_overflow;
581 int64_t account_cpu_limit = large_number_no_overflow;
582 bool greylisted_net =
false;
583 bool greylisted_cpu =
false;
587 uint32_t greylist_limit = config::maximum_elastic_resource_multiplier;
592 greylist_limit = specified_greylist_limit;
595 auto [net_limit, net_was_greylisted] = rl.get_account_net_limit(
a, greylist_limit);
596 if( net_limit >= 0 ) {
597 account_net_limit = std::min( account_net_limit, net_limit );
598 greylisted_net |= net_was_greylisted;
600 auto [cpu_limit, cpu_was_greylisted] = rl.get_account_cpu_limit(
a, greylist_limit);
601 if( cpu_limit >= 0 ) {
602 account_cpu_limit = std::min( account_cpu_limit, cpu_limit );
603 greylisted_cpu |= cpu_was_greylisted;
610 return std::make_tuple(account_net_limit, account_cpu_limit, greylisted_net, greylisted_cpu);
614 SYS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() ,
616 "action_ordinal ${ordinal} is outside allowed range [1,${max}]",
617 (
"ordinal", action_ordinal)(
"max",
trace->action_traces.size())
619 return trace->action_traces[action_ordinal-1];
623 SYS_ASSERT( 0 < action_ordinal && action_ordinal <= trace->action_traces.size() ,
625 "action_ordinal ${ordinal} is outside allowed range [1,${max}]",
626 (
"ordinal", action_ordinal)(
"max",
trace->action_traces.size())
628 return trace->action_traces[action_ordinal-1];
633 uint32_t closest_unnotified_ancestor_action_ordinal )
635 uint32_t new_action_ordinal =
trace->action_traces.size() + 1;
637 trace->action_traces.emplace_back( *
trace, act, receiver, context_free,
638 new_action_ordinal, creator_action_ordinal,
639 closest_unnotified_ancestor_action_ordinal );
641 return new_action_ordinal;
646 uint32_t closest_unnotified_ancestor_action_ordinal )
648 uint32_t new_action_ordinal =
trace->action_traces.size() + 1;
650 trace->action_traces.emplace_back( *
trace, std::move(act), receiver, context_free,
651 new_action_ordinal, creator_action_ordinal,
652 closest_unnotified_ancestor_action_ordinal );
654 return new_action_ordinal;
659 uint32_t closest_unnotified_ancestor_action_ordinal )
661 uint32_t new_action_ordinal =
trace->action_traces.size() + 1;
663 trace->action_traces.reserve( new_action_ordinal );
665 const action& provided_action = get_action_trace( action_ordinal ).
act;
669 trace->action_traces.emplace_back( *
trace, provided_action, receiver, context_free,
670 new_action_ordinal, creator_action_ordinal,
671 closest_unnotified_ancestor_action_ordinal );
673 return new_action_ordinal;
676 void transaction_context::execute_action(
uint32_t action_ordinal,
uint32_t recurse_depth ) {
679 if (recurse_depth == 0) {
681 dm_logger->on_input_action();
689 void transaction_context::schedule_transaction() {
693 if( trx.delay_sec.value == 0 ) {
696 +
static_cast<uint64_t>(config::transaction_id_net_usage) );
702 const auto& cgto =
control.mutable_db().
create<generated_transaction_object>( [&](
auto& gto ) {
704 gto.payer = first_auth;
708 gto.delay_until = gto.published +
delay;
710 trx_size = gto.set( trx );
713 std::string event_id =
RAM_EVENT_ID(
"${id}", (
"id", gto.id));
716 dm_logger->on_ram_trace(std::move(event_id),
"deferred_trx",
"push",
"deferred_trx_pushed");
721 add_ram_usage( cgto.payer, ram_delta );
722 trace->account_ram_delta = account_delta( cgto.payer, ram_delta );
727 control.mutable_db().
create<transaction_object>([&](transaction_object& transaction) {
728 transaction.trx_id =
id;
729 transaction.expiration = expire;
731 }
catch(
const boost::interprocess::bad_alloc& ) {
735 "duplicate transaction ${id}", (
"id",
id ) );
746 "action's code account '${account}' does not exist", (
"account",
a.account) );
748 "context-free actions cannot have authorizations" );
751 flat_set<account_name> actors;
753 bool one_auth =
false;
754 for(
const auto&
a : trx.
actions ) {
757 "action's code account '${account}' does not exist", (
"account",
a.account) );
758 for(
const auto& auth :
a.authorization ) {
762 "action's authorizing actor '${account}' does not exist", (
"account", auth.actor) );
764 "action's authorizations include a non-existent permission: ${permission}",
765 (
"permission", auth) );
766 if( enforce_actor_whitelist_blacklist )
767 actors.insert( auth.actor );
772 if( enforce_actor_whitelist_blacklist ) {
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
const ObjectType & create(Constructor &&con)
static constexpr microseconds maximum()
constexpr uint32_t sec_since_epoch() const
static constexpr time_point maximum()
const global_property_object & get_global_properties() const
const chainbase::database & db() const
bool is_producing_block() const
uint32_t head_block_num() const
void validate_expiration(const transaction &t) const
authorization_manager & get_mutable_authorization_manager()
deep_mind_handler * get_deep_mind_logger() const
std::optional< block_id_type > pending_producer_block_id() const
const authorization_manager & get_authorization_manager() const
void validate_tapos(const transaction &t) const
uint32_t get_greylist_limit() const
bool is_resource_greylisted(const account_name &name) const
void check_actor_list(const flat_set< account_name > &actors) const
time_point pending_block_time() const
bool skip_db_sessions() const
resource_limits_manager & get_mutable_resource_limits_manager()
bool skip_trx_checks() const
chain_config configuration
void add_pending_ram_usage(const account_name account, int64_t ram_delta)
void init_for_deferred_trx(fc::time_point published)
bool explicit_billed_cpu_time
int64_t billed_cpu_time_us
const packed_transaction & packed_trx
void pause_billing_timer()
uint32_t update_billed_cpu_time(fc::time_point now)
transaction_checktime_timer transaction_timer
flat_set< account_name > validate_ram_usage
void resume_billing_timer()
void init_for_implicit_trx(uint64_t initial_net_usage=0)
void add_net_usage(uint64_t u)
transaction_context(controller &c, const packed_transaction &t, transaction_checktime_timer &&timer, fc::time_point start=fc::time_point::now(), bool read_only=false)
fc::time_point block_deadline
transaction_trace_ptr trace
bool enforce_whiteblacklist
friend class apply_context
void validate_referenced_accounts(const transaction &trx, bool enforce_actor_whitelist_blacklist) const
record_transaction
std::optional< chainbase::database::session > undo_session
flat_set< account_name > bill_to_accounts
void check_net_usage() const
std::tuple< int64_t, int64_t, bool, bool > max_bandwidth_billed_accounts_can_pay(bool force_elastic_limits=false) const
void init_for_input_trx(uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size)
controller & control
Fields:
#define RAM_EVENT_ID(FORMAT,...)
constexpr microseconds hours(int64_t h)
constexpr microseconds milliseconds(int64_t s)
constexpr microseconds seconds(int64_t s)
constexpr uint64_t billable_size_v
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type Block can not be found Unlinkable block Block does not guarantee concurrent execution without conflicts Block exhausted allowed resources Block is from the future Block is not signed by expected producer Block includes an ill formed protocol feature activation extension Block includes an ill formed additional block signature extension transaction_exception
checksum_type transaction_id_type
uint128_t transaction_id_to_sender_id(const transaction_id_type &tid)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
unsigned __int64 uint64_t
uint32_t deferred_trx_expiration_window
the number of seconds after the time a deferred transaction can first execute until it expires
const transaction_id_type & id() const
const transaction & get_transaction() const
~transaction_checktime_timer()
void set_expiration_callback(void(*func)(void *), void *user)
std::atomic_bool & expired
transaction_checktime_timer()=delete
void start(fc::time_point tp)
vector< action > context_free_actions
extensions_type transaction_extensions
account_name first_authorizer() const
transaction_checktime_timer & _timer