Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::producer_plugin_impl Class Reference
Inheritance diagram for sysio::producer_plugin_impl:
Collaboration diagram for sysio::producer_plugin_impl:

Public Types

enum class  start_block_result {
  succeeded , failed , waiting_for_block , waiting_for_production ,
  exhausted
}
 
using signature_provider_type = std::function<chain::signature_type(chain::digest_type)>
 
using producer_watermark = std::pair<uint32_t, block_timestamp_type>
 

Public Member Functions

 producer_plugin_impl (boost::asio::io_service &io)
 
std::optional< fc::time_pointcalculate_next_block_time (const account_name &producer_name, const block_timestamp_type &current_block_time) const
 
void schedule_production_loop ()
 
void schedule_maybe_produce_block (bool exhausted)
 
void produce_block ()
 
bool maybe_produce_block ()
 
bool block_is_exhausted () const
 
bool remove_expired_trxs (const fc::time_point &deadline)
 
bool remove_expired_blacklisted_trxs (const fc::time_point &deadline)
 
bool process_unapplied_trxs (const fc::time_point &deadline)
 
void process_scheduled_and_incoming_trxs (const fc::time_point &deadline, size_t &pending_incoming_process_limit)
 
bool process_incoming_trxs (const fc::time_point &deadline, size_t &pending_incoming_process_limit)
 
void consider_new_watermark (account_name producer, uint32_t block_num, block_timestamp_type timestamp)
 
std::optional< producer_watermarkget_watermark (account_name producer) const
 
void on_block (const block_state_ptr &bsp)
 
void on_block_header (const block_state_ptr &bsp)
 
void on_irreversible_block (const signed_block_ptr &lib)
 
void abort_block ()
 
bool on_incoming_block (const signed_block_ptr &block, const std::optional< block_id_type > &block_id, const block_state_ptr &bsp)
 
void restart_speculative_block ()
 
void on_incoming_transaction_async (const packed_transaction_ptr &trx, bool persist_until_expired, bool read_only, bool return_failure_traces, next_function< transaction_trace_ptr > next)
 
bool process_incoming_transaction_async (const transaction_metadata_ptr &trx, bool persist_until_expired, bool return_failure_traces, next_function< transaction_trace_ptr > next)
 
fc::microseconds get_irreversible_block_age ()
 
account_name get_pending_block_producer ()
 
bool production_disabled_by_policy ()
 
bool should_interrupt_start_block (const fc::time_point &deadline) const
 
start_block_result start_block ()
 
fc::time_point calculate_pending_block_time () const
 
fc::time_point calculate_block_deadline (const fc::time_point &) const
 
void schedule_delayed_production_loop (const std::weak_ptr< producer_plugin_impl > &weak_this, std::optional< fc::time_point > wake_up_time)
 
std::optional< fc::time_pointcalculate_producer_wake_up_time (const block_timestamp_type &ref_block_time) const
 

Public Attributes

boost::program_options::variables_map _options
 
bool _production_enabled = false
 
bool _pause_production = false
 
std::map< chain::public_key_type, signature_provider_type_signature_providers
 
std::set< chain::account_name_producers
 
boost::asio::deadline_timer _timer
 
std::map< chain::account_name, producer_watermark_producer_watermarks
 
pending_block_mode _pending_block_mode = pending_block_mode::speculating
 
unapplied_transaction_queue _unapplied_transactions
 
std::optional< named_thread_pool_thread_pool
 
std::atomic< int32_t_max_transaction_time_ms
 
std::atomic< bool > _received_block {false}
 
fc::microseconds _max_irreversible_block_age_us
 
int32_t _produce_time_offset_us = 0
 
int32_t _last_block_time_offset_us = 0
 
uint32_t _max_block_cpu_usage_threshold_us = 0
 
uint32_t _max_block_net_usage_threshold_bytes = 0
 
int32_t _max_scheduled_transaction_time_per_block_ms = 0
 
bool _disable_persist_until_expired = false
 
bool _disable_subjective_p2p_billing = true
 
bool _disable_subjective_api_billing = true
 
fc::time_point _irreversible_block_time
 
fc::microseconds _kiod_provider_timeout_us
 
std::vector< chain::digest_type_protocol_features_to_activate
 
bool _protocol_features_signaled = false
 
chain_pluginchain_plug = nullptr
 
compat::channels::transaction_ack::channel_type_transaction_ack_channel
 
incoming::methods::block_sync::method_type::handle _incoming_block_sync_provider
 
incoming::methods::transaction_async::method_type::handle _incoming_transaction_async_provider
 
transaction_id_with_expiry_index _blacklisted_transactions
 
pending_snapshot_index _pending_snapshot_index
 
subjective_billing _subjective_billing
 
account_failures _account_fails {_subjective_billing}
 
std::optional< scoped_connection > _accepted_block_connection
 
std::optional< scoped_connection > _accepted_block_header_connection
 
std::optional< scoped_connection > _irreversible_block_connection
 
uint32_t _timer_corelation_id = 0
 
double _incoming_defer_ratio = 1.0
 
bfs::path _snapshots_dir
 

Detailed Description

Definition at line 292 of file producer_plugin.cpp.

Member Typedef Documentation

◆ producer_watermark

◆ signature_provider_type

Member Enumeration Documentation

◆ start_block_result

Constructor & Destructor Documentation

◆ producer_plugin_impl()

sysio::producer_plugin_impl::producer_plugin_impl ( boost::asio::io_service & io)
inline

Definition at line 294 of file producer_plugin.cpp.

295 :_timer(io)
296 ,_transaction_ack_channel(app().get_channel<compat::channels::transaction_ack>())
297 {
298 }
compat::channels::transaction_ack::channel_type & _transaction_ack_channel
boost::asio::deadline_timer _timer
application & app()

Member Function Documentation

◆ abort_block()

void sysio::producer_plugin_impl::abort_block ( )
inline

Definition at line 427 of file producer_plugin.cpp.

427 {
428 auto& chain = chain_plug->chain();
429
430 _unapplied_transactions.add_aborted( chain.abort_block() );
432 }
void add_aborted(std::vector< transaction_metadata_ptr > aborted_trxs)
unapplied_transaction_queue _unapplied_transactions
subjective_billing _subjective_billing
Here is the call graph for this function:
Here is the caller graph for this function:

◆ block_is_exhausted()

bool sysio::producer_plugin_impl::block_is_exhausted ( ) const

Definition at line 2238 of file producer_plugin.cpp.

2238 {
2239 const chain::controller& chain = chain_plug->chain();
2240 const auto& rl = chain.get_resource_limits_manager();
2241
2242 const uint64_t cpu_limit = rl.get_block_cpu_limit();
2243 if( cpu_limit < _max_block_cpu_usage_threshold_us ) return true;
2244 const uint64_t net_limit = rl.get_block_net_limit();
2245 if( net_limit < _max_block_net_usage_threshold_bytes ) return true;
2246 return false;
2247}
const resource_limits_manager & get_resource_limits_manager() const
controller_impl
unsigned __int64 uint64_t
Definition stdint.h:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_block_deadline()

fc::time_point sysio::producer_plugin_impl::calculate_block_deadline ( const fc::time_point & block_time) const

Definition at line 1665 of file producer_plugin.cpp.

1665 {
1667 bool last_block = ((block_timestamp_type( block_time ).slot % config::producer_repetitions) == config::producer_repetitions - 1);
1668 return block_time + fc::microseconds(last_block ? _last_block_time_offset_us : _produce_time_offset_us);
1669 } else {
1670 return block_time + fc::microseconds(_produce_time_offset_us);
1671 }
1672}
pending_block_mode _pending_block_mode
block_timestamp< config::block_interval_ms, config::block_timestamp_epoch > block_timestamp_type
Here is the caller graph for this function:

◆ calculate_next_block_time()

std::optional< fc::time_point > sysio::producer_plugin_impl::calculate_next_block_time ( const account_name & producer_name,
const block_timestamp_type & current_block_time ) const

Definition at line 1596 of file producer_plugin.cpp.

1596 {
1597 chain::controller& chain = chain_plug->chain();
1598 const auto& hbs = chain.head_block_state();
1599 const auto& active_schedule = hbs->active_schedule.producers;
1600
1601 // determine if this producer is in the active schedule and if so, where
1602 auto itr = std::find_if(active_schedule.begin(), active_schedule.end(), [&](const auto& asp){ return asp.producer_name == producer_name; });
1603 if (itr == active_schedule.end()) {
1604 // this producer is not in the active producer set
1605 return std::optional<fc::time_point>();
1606 }
1607
1608 size_t producer_index = itr - active_schedule.begin();
1609 uint32_t minimum_offset = 1; // must at least be the "next" block
1610
1611 // account for a watermark in the future which is disqualifying this producer for now
1612 // this is conservative assuming no blocks are dropped. If blocks are dropped the watermark will
1613 // disqualify this producer for longer but it is assumed they will wake up, determine that they
1614 // are disqualified for longer due to skipped blocks and re-caculate their next block with better
1615 // information then
1616 auto current_watermark = get_watermark(producer_name);
1617 if (current_watermark) {
1618 const auto watermark = *current_watermark;
1619 auto block_num = chain.head_block_state()->block_num;
1620 if (chain.is_building_block()) {
1621 ++block_num;
1622 }
1623 if (watermark.first > block_num) {
1624 // if I have a watermark block number then I need to wait until after that watermark
1625 minimum_offset = watermark.first - block_num + 1;
1626 }
1627 if (watermark.second > current_block_time) {
1628 // if I have a watermark block timestamp then I need to wait until after that watermark timestamp
1629 minimum_offset = std::max(minimum_offset, watermark.second.slot - current_block_time.slot + 1);
1630 }
1631 }
1632
1633 // this producers next opportuity to produce is the next time its slot arrives after or at the calculated minimum
1634 uint32_t minimum_slot = current_block_time.slot + minimum_offset;
1635 size_t minimum_slot_producer_index = (minimum_slot % (active_schedule.size() * config::producer_repetitions)) / config::producer_repetitions;
1636 if ( producer_index == minimum_slot_producer_index ) {
1637 // this is the producer for the minimum slot, go with that
1638 return block_timestamp_type(minimum_slot).to_time_point();
1639 } else {
1640 // calculate how many rounds are between the minimum producer and the producer in question
1641 size_t producer_distance = producer_index - minimum_slot_producer_index;
1642 // check for unsigned underflow
1643 if (producer_distance > producer_index) {
1644 producer_distance += active_schedule.size();
1645 }
1646
1647 // align the minimum slot to the first of its set of reps
1648 uint32_t first_minimum_producer_slot = minimum_slot - (minimum_slot % config::producer_repetitions);
1649
1650 // offset the aligned minimum to the *earliest* next set of slots for this producer
1651 uint32_t next_block_slot = first_minimum_producer_slot + (producer_distance * config::producer_repetitions);
1652 return block_timestamp_type(next_block_slot).to_time_point();
1653 }
1654}
fc::time_point to_time_point() const
block_state_ptr head_block_state() const
std::optional< producer_watermark > get_watermark(account_name producer) const
producer_name(block_signing_key)) FC_REFLECT(producer_set_def
unsigned int uint32_t
Definition stdint.h:126
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_pending_block_time()

fc::time_point sysio::producer_plugin_impl::calculate_pending_block_time ( ) const

Definition at line 1656 of file producer_plugin.cpp.

1656 {
1657 const chain::controller& chain = chain_plug->chain();
1658 const fc::time_point now = fc::time_point::now();
1659 const fc::time_point base = std::max<fc::time_point>(now, chain.head_block_time());
1660 const int64_t min_time_to_next_block = (config::block_interval_us) - (base.time_since_epoch().count() % (config::block_interval_us) );
1661 fc::time_point block_time = base + fc::microseconds(min_time_to_next_block);
1662 return block_time;
1663}
static time_point now()
Definition time.cpp:14
signed __int64 int64_t
Definition stdint.h:135
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_producer_wake_up_time()

std::optional< fc::time_point > sysio::producer_plugin_impl::calculate_producer_wake_up_time ( const block_timestamp_type & ref_block_time) const

Definition at line 2332 of file producer_plugin.cpp.

2332 {
2333 // if we have any producers then we should at least set a timer for our next available slot
2334 std::optional<fc::time_point> wake_up_time;
2335 for (const auto& p : _producers) {
2336 auto next_producer_block_time = calculate_next_block_time(p, ref_block_time);
2337 if (next_producer_block_time) {
2338 auto producer_wake_up_time = *next_producer_block_time - fc::microseconds(config::block_interval_us);
2339 if (wake_up_time) {
2340 // wake up with a full block interval to the deadline
2341 if( producer_wake_up_time < *wake_up_time ) {
2342 wake_up_time = producer_wake_up_time;
2343 }
2344 } else {
2345 wake_up_time = producer_wake_up_time;
2346 }
2347 }
2348 }
2349 if( !wake_up_time ) {
2350 fc_dlog(_log, "Not Scheduling Speculative/Production, no local producers had valid wake up times");
2351 }
2352
2353 return wake_up_time;
2354}
const mie::Vuint & p
Definition bn.cpp:27
std::optional< fc::time_point > calculate_next_block_time(const account_name &producer_name, const block_timestamp_type &current_block_time) const
std::set< chain::account_name > _producers
#define fc_dlog(LOGGER, FORMAT,...)
Definition logger.hpp:77
fc::logger _log
Here is the call graph for this function:
Here is the caller graph for this function:

◆ consider_new_watermark()

void sysio::producer_plugin_impl::consider_new_watermark ( account_name producer,
uint32_t block_num,
block_timestamp_type timestamp )
inline

Definition at line 377 of file producer_plugin.cpp.

377 {
378 auto itr = _producer_watermarks.find( producer );
379 if( itr != _producer_watermarks.end() ) {
380 itr->second.first = std::max( itr->second.first, block_num );
381 itr->second.second = std::max( itr->second.second, timestamp );
382 } else if( _producers.count( producer ) > 0 ) {
383 _producer_watermarks.emplace( producer, std::make_pair(block_num, timestamp) );
384 }
385 }
std::map< chain::account_name, producer_watermark > _producer_watermarks
Here is the caller graph for this function:

◆ get_irreversible_block_age()

fc::microseconds sysio::producer_plugin_impl::get_irreversible_block_age ( )
inline

Definition at line 763 of file producer_plugin.cpp.

763 {
764 auto now = fc::time_point::now();
765 if (now < _irreversible_block_time) {
766 return fc::microseconds(0);
767 } else {
768 return now - _irreversible_block_time;
769 }
770 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_pending_block_producer()

account_name sysio::producer_plugin_impl::get_pending_block_producer ( )
inline

Definition at line 772 of file producer_plugin.cpp.

772 {
773 auto& chain = chain_plug->chain();
774 if (chain.is_building_block()) {
775 return chain.pending_block_producer();
776 } else {
777 return {};
778 }
779 }

◆ get_watermark()

std::optional< producer_watermark > sysio::producer_plugin_impl::get_watermark ( account_name producer) const
inline

Definition at line 387 of file producer_plugin.cpp.

387 {
388 auto itr = _producer_watermarks.find( producer );
389
390 if( itr == _producer_watermarks.end() ) return {};
391
392 return itr->second;
393 }
Here is the caller graph for this function:

◆ maybe_produce_block()

bool sysio::producer_plugin_impl::maybe_produce_block ( )

Definition at line 2372 of file producer_plugin.cpp.

2372 {
2373 auto reschedule = fc::make_scoped_exit([this]{
2375 });
2376
2377 try {
2378 produce_block();
2379 return true;
2380 } LOG_AND_DROP();
2381
2382 fc_dlog(_log, "Aborting block due to produce_block error");
2383 abort_block();
2384 return false;
2385}
scoped_exit< Callback > make_scoped_exit(Callback &&c)
#define LOG_AND_DROP()
Here is the call graph for this function:

◆ on_block()

void sysio::producer_plugin_impl::on_block ( const block_state_ptr & bsp)
inline

Definition at line 395 of file producer_plugin.cpp.

395 {
396 auto before = _unapplied_transactions.size();
399 fc_dlog( _log, "Removed applied transactions before: ${before}, after: ${after}",
400 ("before", before)("after", _unapplied_transactions.size()) );
401 }
void on_block(fc::logger &log, const block_state_ptr &bsp, const fc::time_point &now)
Here is the call graph for this function:

◆ on_block_header()

void sysio::producer_plugin_impl::on_block_header ( const block_state_ptr & bsp)
inline

Definition at line 403 of file producer_plugin.cpp.

403 {
404 consider_new_watermark( bsp->header.producer, bsp->block_num, bsp->block->timestamp );
405 }
void consider_new_watermark(account_name producer, uint32_t block_num, block_timestamp_type timestamp)
Here is the call graph for this function:

◆ on_incoming_block()

bool sysio::producer_plugin_impl::on_incoming_block ( const signed_block_ptr & block,
const std::optional< block_id_type > & block_id,
const block_state_ptr & bsp )
inline

Definition at line 434 of file producer_plugin.cpp.

434 {
435 auto& chain = chain_plug->chain();
437 fc_wlog( _log, "dropped incoming block #${num} id: ${id}",
438 ("num", block->block_num())("id", block_id ? (*block_id).str() : "UNKNOWN") );
439 return false;
440 }
441
442 // start a new speculative block, speculative start_block may have been interrupted
443 auto ensure = fc::make_scoped_exit([this](){
445 });
446
447 const auto& id = block_id ? *block_id : block->calculate_id();
448 auto blk_num = block->block_num();
449
450 fc_dlog(_log, "received incoming block ${n} ${id}", ("n", blk_num)("id", id));
451
452 SYS_ASSERT( block->timestamp < (fc::time_point::now() + fc::seconds( 7 )), block_from_the_future,
453 "received a block from the future, ignoring it: ${id}", ("id", id) );
454
455 /* de-dupe here... no point in aborting block if we already know the block */
456 auto existing = chain.fetch_block_by_id( id );
457 if( existing ) { return false; }
458
459 // start processing of block
460 std::future<block_state_ptr> bsf;
461 if( !bsp ) {
462 bsf = chain.create_block_state_future( id, block );
463 }
464
465 // abort the pending block
466 abort_block();
467
468 // push the new block
469 auto handle_error = [&](const auto& e)
470 {
471 elog((e.to_detail_string()));
473 throw;
474 };
475
476 try {
477 const block_state_ptr& bspr = bsp ? bsp : bsf.get();
478 chain.push_block( bspr, [this]( const branch_type& forked_branch ) {
479 _unapplied_transactions.add_forked( forked_branch );
480 }, [this]( const transaction_id_type& id ) {
481 return _unapplied_transactions.get_trx( id );
482 } );
483 } catch ( const guard_exception& e ) {
485 return false;
486 } catch ( const std::bad_alloc& ) {
488 } catch ( boost::interprocess::bad_alloc& ) {
490 } catch ( const fork_database_exception& e ) {
491 elog("Cannot recover from ${e}. Shutting down.", ("e", e.to_detail_string()));
492 appbase::app().quit();
493 } catch( const fc::exception& e ) {
494 handle_error(e);
495 } catch (const std::exception& e) {
497 }
498
499 const auto& hbs = chain.head_block_state();
500 if( hbs->header.timestamp.next().to_time_point() >= fc::time_point::now() ) {
501 _production_enabled = true;
502 }
503
504 if( fc::time_point::now() - block->timestamp < fc::minutes(5) || (blk_num % 1000 == 0) ) {
505 ilog("Received block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, conf: ${confs}, latency: ${latency} ms]",
506 ("p",block->producer)("id",id.str().substr(8,16))("n",blk_num)("t",block->timestamp)
507 ("count",block->transactions.size())("lib",chain.last_irreversible_block_num())
508 ("confs", block->confirmed)("latency", (fc::time_point::now() - block->timestamp).count()/1000 ) );
509 if( chain.get_read_mode() != db_read_mode::IRREVERSIBLE && hbs->id != id && hbs->block != nullptr ) { // not applied to head
510 ilog("Block not applied to head ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, dpos: ${dpos}, conf: ${confs}, latency: ${latency} ms]",
511 ("p",hbs->block->producer)("id",hbs->id.str().substr(8,16))("n",hbs->block_num)("t",hbs->block->timestamp)
512 ("count",hbs->block->transactions.size())("dpos", hbs->dpos_irreversible_blocknum)
513 ("confs", hbs->block->confirmed)("latency", (fc::time_point::now() - hbs->block->timestamp).count()/1000 ) );
514 }
515 }
516
517 return true;
518 }
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
auto get_channel() -> std::enable_if_t< is_channel_decl< ChannelDecl >::value, typename ChannelDecl::channel_type & >
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
static std_exception_wrapper from_current_exception(const std::exception &e)
void add_forked(const branch_type &forked_branch)
transaction_metadata_ptr get_trx(const transaction_id_type &id) const
static void handle_db_exhaustion()
static void handle_guard_exception(const chain::guard_exception &e)
static void handle_bad_alloc()
uint64_t id
Definition code_cache.cpp:0
#define ilog(FORMAT,...)
Definition logger.hpp:118
#define elog(FORMAT,...)
Definition logger.hpp:130
#define fc_wlog(LOGGER, FORMAT,...)
Definition logger.hpp:89
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
constexpr microseconds minutes(int64_t m)
Definition time.hpp:34
channel_decl< struct rejected_block_tag, signed_block_ptr > rejected_block
deque< block_state_ptr > branch_type
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 Error decompressing transaction Transaction should have at least one required authority Expired Transaction Invalid Reference Block Duplicate deferred transaction The transaction can not be found Transaction is too big Invalid transaction extension Transaction includes disallowed Transaction exceeded transient resource limit Account name already exists sysio_assert_message assertion failure Action can not be found Attempt to use unaccessible API Inline Action exceeds maximum size limit sysio_assert_code assertion failure uses restricted error code value action return value size too big Permission Query Exception Contract Table Query Exception Database is an unknown or unsupported version guard_exception
checksum_type transaction_id_type
Definition types.hpp:236
std::shared_ptr< block_state > block_state_ptr
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type fork_database_exception
static constexpr int medium
void bsf(const Reg &reg, const Operand &op)
Here is the call graph for this function:

◆ on_incoming_transaction_async()

void sysio::producer_plugin_impl::on_incoming_transaction_async ( const packed_transaction_ptr & trx,
bool persist_until_expired,
bool read_only,
bool return_failure_traces,
next_function< transaction_trace_ptr > next )
inline

Definition at line 528 of file producer_plugin.cpp.

532 {
533 chain::controller& chain = chain_plug->chain();
534 const auto max_trx_time_ms = _max_transaction_time_ms.load();
535 fc::microseconds max_trx_cpu_usage = max_trx_time_ms < 0 ? fc::microseconds::maximum() : fc::milliseconds( max_trx_time_ms );
536
537 auto future = transaction_metadata::start_recover_keys( trx, _thread_pool->get_executor(),
538 chain.get_chain_id(), fc::microseconds( max_trx_cpu_usage ),
539 read_only ? transaction_metadata::trx_type::read_only : transaction_metadata::trx_type::input,
540 chain.configured_subjective_signature_length_limit() );
541
542 boost::asio::post(_thread_pool->get_executor(), [self = this, future{std::move(future)}, persist_until_expired, return_failure_traces,
543 next{std::move(next)}, trx]() mutable {
544 if( future.valid() ) {
545 future.wait();
546 app().post( priority::low, [self, future{std::move(future)}, persist_until_expired, next{std::move( next )}, trx{std::move(trx)}, return_failure_traces]() mutable {
547 auto exception_handler = [self, &next, trx{std::move(trx)}](fc::exception_ptr ex) {
548 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${txid}, auth: ${a} : ${why} ",
549 ("txid", trx->id())("a",trx->get_transaction().first_authorizer())("why",ex->what()));
550 next(ex);
551
552 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${entire_trx}",
553 ("entire_trx", self->chain_plug->get_log_trx(trx->get_transaction())));
554 fc_dlog(_trx_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${trx}",
555 ("trx", self->chain_plug->get_log_trx(trx->get_transaction())));
556 };
557 try {
558 auto result = future.get();
559 if( !self->process_incoming_transaction_async( result, persist_until_expired, return_failure_traces, next) ) {
560 if( self->_pending_block_mode == pending_block_mode::producing ) {
561 self->schedule_maybe_produce_block( true );
562 } else {
563 self->restart_speculative_block();
564 }
565 }
566 } CATCH_AND_CALL(exception_handler);
567 } );
568 }
569 });
570 }
static constexpr microseconds maximum()
Definition time.hpp:14
static recover_keys_future start_recover_keys(packed_transaction_ptr trx, boost::asio::io_context &thread_pool, const chain_id_type &chain_id, fc::microseconds time_limit, trx_type t, uint32_t max_variable_sig_size=UINT32_MAX)
std::atomic< int32_t > _max_transaction_time_ms
std::optional< named_thread_pool > _thread_pool
namespace sysio::chain
Definition authority.cpp:3
@ read_only
constexpr microseconds milliseconds(int64_t s)
Definition time.hpp:33
@ self
the connection is to itself
Definition protocol.hpp:48
Here is the call graph for this function:

◆ on_irreversible_block()

void sysio::producer_plugin_impl::on_irreversible_block ( const signed_block_ptr & lib)
inline

Definition at line 407 of file producer_plugin.cpp.

407 {
408 _irreversible_block_time = lib->timestamp.to_time_point();
409 const chain::controller& chain = chain_plug->chain();
410
411 // promote any pending snapshots
412 auto& snapshots_by_height = _pending_snapshot_index.get<by_height>();
413 uint32_t lib_height = lib->block_num();
414
415 while (!snapshots_by_height.empty() && snapshots_by_height.begin()->get_height() <= lib_height) {
416 const auto& pending = snapshots_by_height.begin();
417 auto next = pending->next;
418
419 try {
420 next(pending->finalize(chain));
421 } CATCH_AND_CALL(next);
422
423 snapshots_by_height.erase(snapshots_by_height.begin());
424 }
425 }
#define CATCH_AND_CALL(NEXT)
pending_snapshot_index _pending_snapshot_index
uint32_t next(octet_iterator &it, octet_iterator end)
Definition checked.h:137
Here is the call graph for this function:

◆ process_incoming_transaction_async()

bool sysio::producer_plugin_impl::process_incoming_transaction_async ( const transaction_metadata_ptr & trx,
bool persist_until_expired,
bool return_failure_traces,
next_function< transaction_trace_ptr > next )
inline

Definition at line 572 of file producer_plugin.cpp.

575 {
576 bool exhausted = false;
577 chain::controller& chain = chain_plug->chain();
578
579 auto send_response = [this, &trx, &chain, &next](const std::variant<fc::exception_ptr, transaction_trace_ptr>& response) {
580 next(response);
581
582 auto get_trace = [&](const std::variant<fc::exception_ptr, transaction_trace_ptr>& response) -> fc::variant {
583 if (std::holds_alternative<fc::exception_ptr>(response)) {
584 return fc::variant{std::get<fc::exception_ptr>(response)};
585 } else {
586 return chain_plug->get_log_trx_trace( std::get<transaction_trace_ptr>(response) );
587 }
588
589 };
590
591 fc::exception_ptr except_ptr; // rejected
592 if (std::holds_alternative<fc::exception_ptr>(response)) {
593 except_ptr = std::get<fc::exception_ptr>(response);
594 } else if (std::get<transaction_trace_ptr>(response)->except) {
595 except_ptr = std::get<transaction_trace_ptr>(response)->except->dynamic_copy_exception();
596 }
597
598 if (!trx->read_only) {
599 _transaction_ack_channel.publish(priority::low, std::pair<fc::exception_ptr, packed_transaction_ptr>(except_ptr, trx->packed_trx()));
600 }
601
602 if (except_ptr) {
604 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${txid}, auth: ${a} : ${why} ",
605 ("block_num", chain.head_block_num() + 1)
607 ("txid", trx->id())
608 ("a", trx->packed_trx()->get_transaction().first_authorizer())
609 ("why", except_ptr->what()));
610 fc_dlog(_trx_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${trx}",
611 ("block_num", chain.head_block_num() + 1)("prod", get_pending_block_producer())
612 ("trx", chain_plug->get_log_trx(trx->packed_trx()->get_transaction())));
613 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is REJECTING tx: ${entire_trace}",
614 ("block_num", chain.head_block_num() + 1)("prod", get_pending_block_producer())
615 ("entire_trace", get_trace(response)));
616 } else {
617 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${txid}, auth: ${a} : ${why} ",
618 ("txid", trx->id())
619 ("a", trx->packed_trx()->get_transaction().first_authorizer())
620 ("why", except_ptr->what()));
621 fc_dlog(_trx_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${trx} ",
622 ("trx", chain_plug->get_log_trx(trx->packed_trx()->get_transaction())));
623 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Speculative execution is REJECTING tx: ${entire_trace} ",
624 ("entire_trace", get_trace(response)));
625 }
626 } else {
628 fc_dlog(_trx_successful_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${txid}, auth: ${a}, cpu: ${cpu}",
629 ("block_num", chain.head_block_num() + 1)
631 ("txid", trx->id())
632 ("a", trx->packed_trx()->get_transaction().first_authorizer())
633 ("cpu", trx->billed_cpu_time_us));
634 fc_dlog(_trx_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${trx}",
635 ("block_num", chain.head_block_num() + 1)("prod", get_pending_block_producer())
636 ("trx", chain_plug->get_log_trx(trx->packed_trx()->get_transaction())));
637 fc_dlog(_trx_trace_success_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is ACCEPTING tx: ${entire_trace}",
638 ("block_num", chain.head_block_num() + 1)("prod", get_pending_block_producer())
639 ("entire_trace", get_trace(response)));
640 } else {
641 fc_dlog(_trx_successful_trace_log, "[TRX_TRACE] Speculative execution is ACCEPTING tx: ${txid}, auth: ${a}, cpu: ${cpu}",
642 ("txid", trx->id())
643 ("a", trx->packed_trx()->get_transaction().first_authorizer())
644 ("cpu", trx->billed_cpu_time_us));
645 fc_dlog(_trx_trace_success_log, "[TRX_TRACE] Speculative execution is ACCEPTING tx: ${entire_trace}",
646 ("entire_trace", get_trace(response)));
647 fc_dlog(_trx_log, "[TRX_TRACE] Speculative execution is ACCEPTING tx: ${trx}",
648 ("trx", chain_plug->get_log_trx(trx->packed_trx()->get_transaction())));
649 }
650 }
651 };
652
653 try {
654 const auto& id = trx->id();
655
656 fc::time_point bt = chain.is_building_block() ? chain.pending_block_time() : chain.head_block_time();
657 const fc::time_point expire = trx->packed_trx()->expiration();
658 if( expire < bt ) {
659 send_response( std::static_pointer_cast<fc::exception>(
660 std::make_shared<expired_tx_exception>(
661 FC_LOG_MESSAGE( error, "expired transaction ${id}, expiration ${e}, block time ${bt}",
662 ("id", id)("e", expire)( "bt", bt )))));
663 return true;
664 }
665
666 if( chain.is_known_unexpired_transaction( id )) {
667 send_response( std::static_pointer_cast<fc::exception>( std::make_shared<tx_duplicate>(
668 FC_LOG_MESSAGE( error, "duplicate transaction ${id}", ("id", id)))) );
669 return true;
670 }
671
672 if( !chain.is_building_block()) {
673 _unapplied_transactions.add_incoming( trx, persist_until_expired, return_failure_traces, next );
674 return true;
675 }
676
677 auto first_auth = trx->packed_trx()->get_transaction().first_authorizer();
678 if( _account_fails.failure_limit( first_auth ) ) {
679 send_response( std::static_pointer_cast<fc::exception>( std::make_shared<tx_cpu_usage_exceeded>(
680 FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a}",
681 ("id", trx->id())("a", first_auth) ) ) ) );
682 return true;
683 }
684
685 auto start = fc::time_point::now();
687 if( max_trx_time.count() < 0 ) max_trx_time = fc::microseconds::maximum();
688 const auto block_deadline = calculate_block_deadline( chain.pending_block_time() );
689
690 bool disable_subjective_billing = ( _pending_block_mode == pending_block_mode::producing )
691 || ( persist_until_expired && _disable_subjective_api_billing )
692 || ( !persist_until_expired && _disable_subjective_p2p_billing )
693 || trx->read_only;
694
695 int64_t sub_bill = 0;
696 if( !disable_subjective_billing )
698
699 auto prev_billed_cpu_time_us = trx->billed_cpu_time_us;
700 auto trace = chain.push_transaction( trx, block_deadline, max_trx_time, prev_billed_cpu_time_us, false, sub_bill );
701 fc_dlog( _trx_failed_trace_log, "Subjective bill for ${a}: ${b} elapsed ${t}us", ("a",first_auth)("b",sub_bill)("t",trace->elapsed));
702 if( trace->except ) {
703 if( exception_is_exhausted( *trace->except ) ) {
704 _unapplied_transactions.add_incoming( trx, persist_until_expired, return_failure_traces, next );
706 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} COULD NOT FIT, tx: ${txid} RETRYING ",
707 ("block_num", chain.head_block_num() + 1)
709 ("txid", trx->id()));
710 } else {
711 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Speculative execution COULD NOT FIT tx: ${txid} RETRYING",
712 ("txid", trx->id()));
713 }
715 } else {
716 if (!disable_subjective_billing)
717 _subjective_billing.subjective_bill_failure( first_auth, trace->elapsed, fc::time_point::now() );
718
720 auto failure_code = trace->except->code();
721 if( failure_code != tx_duplicate::code_value ) {
722 // this failed our configured maximum transaction time, we don't want to replay it
723 fc_dlog( _log, "Failed ${c} trx, prev billed: ${p}us, ran: ${r}us, id: ${id}",
724 ("c", trace->except->code())( "p", prev_billed_cpu_time_us )
725 ( "r", fc::time_point::now() - start )( "id", trx->id() ) );
726 _account_fails.add( first_auth, failure_code );
727 }
728 }
729 if( return_failure_traces ) {
730 send_response( trace );
731 } else {
732 auto e_ptr = trace->except->dynamic_copy_exception();
733 send_response( e_ptr );
734 }
735 }
736 } else {
737 if( persist_until_expired && !_disable_persist_until_expired ) {
738 // if this trx didnt fail/soft-fail and the persist flag is set, store its ID so that we can
739 // ensure its applied to all future speculative blocks as well.
740 // No need to subjective bill since it will be re-applied
742 } else {
743 // if db_read_mode SPECULATIVE then trx is in the pending block and not immediately reverted
744 if (!disable_subjective_billing)
745 _subjective_billing.subjective_bill( trx->id(), expire, first_auth, trace->elapsed,
746 chain.get_read_mode() == chain::db_read_mode::SPECULATIVE );
747 }
748 send_response( trace );
749 }
750
751 } catch ( const guard_exception& e ) {
753 } catch ( boost::interprocess::bad_alloc& ) {
755 } catch ( std::bad_alloc& ) {
757 } CATCH_AND_CALL(send_response);
758
759 return !exhausted;
760 }
void publish(int priority, const Data &data)
constexpr int64_t count() const
Definition time.hpp:26
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
void add_incoming(const transaction_metadata_ptr &trx, bool persist_until_expired, bool return_failure_trace, next_func_t next)
void add_persisted(const transaction_metadata_ptr &trx)
fc::variant get_log_trx_trace(const chain::transaction_trace_ptr &trx_trace) const
fc::variant get_log_trx(const transaction &trx) const
fc::time_point calculate_block_deadline(const fc::time_point &) const
account_name get_pending_block_producer()
int64_t get_subjective_bill(const account_name &first_auth, const fc::time_point &now) const
void subjective_bill(const transaction_id_type &id, const fc::time_point &expire, const account_name &first_auth, const fc::microseconds &elapsed, bool in_pending_block)
void subjective_bill_failure(const account_name &first_auth, const fc::microseconds &elapsed, const fc::time_point &now)
#define FC_LOG_MESSAGE(LOG_LEVEL, FORMAT,...)
A helper method for generating log messages.
std::shared_ptr< exception > exception_ptr
fc::logger _trx_log
fc::logger _trx_trace_success_log
fc::logger _trx_trace_failure_log
fc::logger _trx_failed_trace_log
fc::logger _trx_successful_trace_log
void bt(const Operand &op, const Reg &reg)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_incoming_trxs()

bool sysio::producer_plugin_impl::process_incoming_trxs ( const fc::time_point & deadline,
size_t & pending_incoming_process_limit )

Definition at line 2207 of file producer_plugin.cpp.

2208{
2209 bool exhausted = false;
2210 if( pending_incoming_process_limit ) {
2211 size_t processed = 0;
2212 fc_dlog( _log, "Processing ${n} pending transactions", ("n", pending_incoming_process_limit) );
2215 while( pending_incoming_process_limit && itr != end ) {
2216 if ( should_interrupt_start_block( deadline ) ) {
2217 exhausted = true;
2218 break;
2219 }
2220 --pending_incoming_process_limit;
2221
2222 auto trx_meta = itr->trx_meta;
2223 auto next = itr->next;
2224 bool persist_until_expired = itr->trx_type == trx_enum_type::incoming_persisted;
2225 bool return_failure_trace = itr->return_failure_trace;
2226 itr = _unapplied_transactions.erase( itr );
2227 if( !process_incoming_transaction_async( trx_meta, persist_until_expired, return_failure_trace, next ) ) {
2228 exhausted = true;
2229 break;
2230 }
2231 ++processed;
2232 }
2233 fc_dlog( _log, "Processed ${n} pending transactions, ${p} left", ("n", processed)("p", _unapplied_transactions.incoming_size()) );
2234 }
2235 return !exhausted;
2236}
iterator erase(iterator itr)
caller's responsibility to call next() if applicable
bool should_interrupt_start_block(const fc::time_point &deadline) const
bool process_incoming_transaction_async(const transaction_metadata_ptr &trx, bool persist_until_expired, bool return_failure_traces, next_function< transaction_trace_ptr > next)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_scheduled_and_incoming_trxs()

void sysio::producer_plugin_impl::process_scheduled_and_incoming_trxs ( const fc::time_point & deadline,
size_t & pending_incoming_process_limit )

Definition at line 2104 of file producer_plugin.cpp.

2105{
2106 // scheduled transactions
2107 int num_applied = 0;
2108 int num_failed = 0;
2109 int num_processed = 0;
2110 bool exhausted = false;
2111 double incoming_trx_weight = 0.0;
2112
2113 auto& blacklist_by_id = _blacklisted_transactions.get<by_id>();
2114 chain::controller& chain = chain_plug->chain();
2115 time_point pending_block_time = chain.pending_block_time();
2118 const auto& sch_idx = chain.db().get_index<generated_transaction_multi_index,by_delay>();
2119 const auto scheduled_trxs_size = sch_idx.size();
2120 auto sch_itr = sch_idx.begin();
2121 while( sch_itr != sch_idx.end() ) {
2122 if( sch_itr->delay_until > pending_block_time) break; // not scheduled yet
2123 if( exhausted || deadline <= fc::time_point::now() ) {
2124 exhausted = true;
2125 break;
2126 }
2127 if( sch_itr->published >= pending_block_time ) {
2128 ++sch_itr;
2129 continue; // do not allow schedule and execute in same block
2130 }
2131
2132 if (blacklist_by_id.find(sch_itr->trx_id) != blacklist_by_id.end()) {
2133 ++sch_itr;
2134 continue;
2135 }
2136
2137 const transaction_id_type trx_id = sch_itr->trx_id; // make copy since reference could be invalidated
2138 const auto sch_expiration = sch_itr->expiration;
2139 auto sch_itr_next = sch_itr; // save off next since sch_itr may be invalidated by loop
2140 ++sch_itr_next;
2141 const auto next_delay_until = sch_itr_next != sch_idx.end() ? sch_itr_next->delay_until : sch_itr->delay_until;
2142 const auto next_id = sch_itr_next != sch_idx.end() ? sch_itr_next->id : sch_itr->id;
2143
2144 num_processed++;
2145
2146 // configurable ratio of incoming txns vs deferred txns
2147 while (incoming_trx_weight >= 1.0 && pending_incoming_process_limit && itr != end ) {
2148 if (deadline <= fc::time_point::now()) {
2149 exhausted = true;
2150 break;
2151 }
2152
2153 --pending_incoming_process_limit;
2154 incoming_trx_weight -= 1.0;
2155
2156 auto trx_meta = itr->trx_meta;
2157 auto next = itr->next;
2158 bool persist_until_expired = itr->trx_type == trx_enum_type::incoming_persisted;
2159 bool return_failure_trace = itr->return_failure_trace;
2160 itr = _unapplied_transactions.erase( itr );
2161 if( !process_incoming_transaction_async( trx_meta, persist_until_expired, return_failure_trace, next ) ) {
2162 exhausted = true;
2163 break;
2164 }
2165 }
2166
2167 if (exhausted || deadline <= fc::time_point::now()) {
2168 exhausted = true;
2169 break;
2170 }
2171
2172 try {
2174 if( max_trx_time.count() < 0 ) max_trx_time = fc::microseconds::maximum();
2175
2176 auto trace = chain.push_scheduled_transaction(trx_id, deadline, max_trx_time, 0, false);
2177 if (trace->except) {
2178 if (exception_is_exhausted(*trace->except)) {
2179 if( block_is_exhausted() ) {
2180 exhausted = true;
2181 break;
2182 }
2183 } else {
2184 // this failed our configured maximum transaction time, we don't want to replay it add it to a blacklist
2185 _blacklisted_transactions.insert(transaction_id_with_expiry{trx_id, sch_expiration});
2186 num_failed++;
2187 }
2188 } else {
2189 num_applied++;
2190 }
2191 } LOG_AND_DROP();
2192
2193 incoming_trx_weight += _incoming_defer_ratio;
2194 if (!pending_incoming_process_limit) incoming_trx_weight = 0.0;
2195
2196 if( sch_itr_next == sch_idx.end() ) break;
2197 sch_itr = sch_idx.lower_bound( boost::make_tuple( next_delay_until, next_id ) );
2198 }
2199
2200 if( scheduled_trxs_size > 0 ) {
2201 fc_dlog( _log,
2202 "Processed ${m} of ${n} scheduled transactions, Applied ${applied}, Failed/Dropped ${failed}",
2203 ( "m", num_processed )( "n", scheduled_trxs_size )( "applied", num_applied )( "failed", num_failed ) );
2204 }
2205}
transaction_id_with_expiry_index _blacklisted_transactions
chainbase::shared_multi_index_container< generated_transaction_object, indexed_by< ordered_unique< tag< by_id >, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, generated_transaction_object::id_type, id)>, ordered_unique< tag< by_trx_id >, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, transaction_id_type, trx_id)>, ordered_unique< tag< by_expiration >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, time_point, expiration), > >, ordered_unique< tag< by_delay >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, time_point, delay_until), > >, ordered_unique< tag< by_sender_id >, composite_key< generated_transaction_object, BOOST_MULTI_INDEX_MEMBER(generated_transaction_object, account_name, sender), > > > > generated_transaction_multi_index
Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_unapplied_trxs()

bool sysio::producer_plugin_impl::process_unapplied_trxs ( const fc::time_point & deadline)

Definition at line 2001 of file producer_plugin.cpp.

2002{
2003 bool exhausted = false;
2005 chain::controller& chain = chain_plug->chain();
2006 const auto& rl = chain.get_resource_limits_manager();
2007 int num_applied = 0, num_failed = 0, num_processed = 0;
2008 auto unapplied_trxs_size = _unapplied_transactions.size();
2009 // unapplied and persisted do not have a next method to call
2014 while( itr != end_itr ) {
2015 if( should_interrupt_start_block( deadline ) ) {
2016 exhausted = true;
2017 break;
2018 }
2019
2020 const transaction_metadata_ptr trx = itr->trx_meta;
2021 ++num_processed;
2022 try {
2023 auto start = fc::time_point::now();
2024
2025 auto first_auth = trx->packed_trx()->get_transaction().first_authorizer();
2026 if( _account_fails.failure_limit( first_auth ) ) {
2027 ++num_failed;
2028 if( itr->next ) {
2029 itr->next( std::make_shared<tx_cpu_usage_exceeded>(
2030 FC_LOG_MESSAGE( error, "transaction ${id} exceeded failure limit for account ${a}",
2031 ("id", trx->id())("a", first_auth) ) ) );
2032 }
2033 itr = _unapplied_transactions.erase( itr );
2034 continue;
2035 }
2036
2038 if( max_trx_time.count() < 0 ) max_trx_time = fc::microseconds::maximum();
2039
2040 auto prev_billed_cpu_time_us = trx->billed_cpu_time_us;
2041 if( prev_billed_cpu_time_us > 0 && !_subjective_billing.is_account_disabled( first_auth ) && !rl.is_unlimited_cpu( first_auth )) {
2042 uint64_t prev_billed_plus100_us = prev_billed_cpu_time_us + SYS_PERCENT( prev_billed_cpu_time_us, 100 * config::percent_1 );
2043 if( prev_billed_plus100_us < max_trx_time.count() ) max_trx_time = fc::microseconds( prev_billed_plus100_us );
2044 }
2045
2046 // no subjective billing since we are producing or processing persisted trxs
2047 const int64_t sub_bill = 0;
2048 bool disable_subjective_billing = ( _pending_block_mode == pending_block_mode::producing )
2049 || ( (itr->trx_type == trx_enum_type::persisted) && _disable_subjective_api_billing )
2050 || ( !(itr->trx_type == trx_enum_type::persisted) && _disable_subjective_p2p_billing )
2051 || trx->read_only;
2052
2053 auto trace = chain.push_transaction( trx, deadline, max_trx_time, prev_billed_cpu_time_us, false, sub_bill );
2054 fc_dlog( _trx_failed_trace_log, "Subjective unapplied bill for ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
2055 if( trace->except ) {
2056 if( exception_is_exhausted( *trace->except ) ) {
2057 if( block_is_exhausted() ) {
2058 exhausted = true;
2059 // don't erase, subjective failure so try again next time
2060 break;
2061 }
2062 } else {
2063 fc_dlog( _trx_failed_trace_log, "Subjective unapplied bill for failed ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
2064 auto failure_code = trace->except->code();
2065 if( failure_code != tx_duplicate::code_value ) {
2066 // this failed our configured maximum transaction time, we don't want to replay it
2067 fc_dlog( _log, "Failed ${c} trx, prev billed: ${p}us, ran: ${r}us, id: ${id}",
2068 ("c", trace->except->code())("p", prev_billed_cpu_time_us)
2069 ("r", fc::time_point::now() - start)("id", trx->id()) );
2070 _account_fails.add( first_auth, failure_code );
2071 if (!disable_subjective_billing)
2072 _subjective_billing.subjective_bill_failure( first_auth, trace->elapsed, fc::time_point::now() );
2073 }
2074 ++num_failed;
2075 if( itr->next ) {
2076 itr->next( trace->except->dynamic_copy_exception() );
2077 }
2078 itr = _unapplied_transactions.erase( itr );
2079 continue;
2080 }
2081 } else {
2082 fc_dlog( _trx_successful_trace_log, "Subjective unapplied bill for success ${a}: ${b} prev ${t}us", ("a",first_auth)("b",prev_billed_cpu_time_us)("t",trace->elapsed));
2083 // if db_read_mode SPECULATIVE then trx is in the pending block and not immediately reverted
2084 if (!disable_subjective_billing)
2085 _subjective_billing.subjective_bill( trx->id(), trx->packed_trx()->expiration(), first_auth, trace->elapsed,
2086 chain.get_read_mode() == chain::db_read_mode::SPECULATIVE );
2087 ++num_applied;
2088 if( itr->trx_type != trx_enum_type::persisted ) {
2089 if( itr->next ) itr->next( trace );
2090 itr = _unapplied_transactions.erase( itr );
2091 continue;
2092 }
2093 }
2094 } LOG_AND_DROP();
2095 ++itr;
2096 }
2097
2098 fc_dlog( _log, "Processed ${m} of ${n} previously applied transactions, Applied ${applied}, Failed/Dropped ${failed}",
2099 ("m", num_processed)( "n", unapplied_trxs_size )("applied", num_applied)("failed", num_failed) );
2100 }
2101 return !exhausted;
2102}
constexpr uint64_t SYS_PERCENT(uint64_t value, uint32_t percentage)
Definition config.hpp:152
bool is_account_disabled(const account_name &a) const
std::shared_ptr< transaction_metadata > transaction_metadata_ptr
Here is the call graph for this function:
Here is the caller graph for this function:

◆ produce_block()

void sysio::producer_plugin_impl::produce_block ( )

S-ROOT HEADER EXTENSION

Definition at line 2402 of file producer_plugin.cpp.

2402 {
2403 //ilog("produce_block ${t}", ("t", fc::time_point::now())); // for testing _produce_time_offset_us
2404 SYS_ASSERT(_pending_block_mode == pending_block_mode::producing, producer_exception, "called produce_block while not actually producing");
2405 chain::controller& chain = chain_plug->chain();
2406 SYS_ASSERT(chain.is_building_block(), missing_pending_block_state, "pending_block_state does not exist but it should, another plugin may have corrupted it");
2407
2408 const auto& auth = chain.pending_block_signing_authority();
2409 std::vector<std::reference_wrapper<const signature_provider_type>> relevant_providers;
2410
2411 relevant_providers.reserve(_signature_providers.size());
2412
2414 const auto& iter = _signature_providers.find(key);
2415 if (iter != _signature_providers.end()) {
2416 relevant_providers.emplace_back(iter->second);
2417 }
2418 });
2419
2420 SYS_ASSERT(relevant_providers.size() > 0, producer_priv_key_not_found, "Attempting to produce a block for which we don't have any relevant private keys");
2421
2423 _protocol_features_to_activate.clear(); // clear _protocol_features_to_activate as it is already set in pending_block
2425 }
2426
2430 auto& sub_chain_plug = app().get_plugin<sub_chain_plugin>();
2431 // TODO: verify sub chain is enabled, otherwise skip? or require?
2432 // Step 1: Scans transactions to find relevant transactions by comparing to a list of known contracts.
2433 auto relevant_s_transactions = sub_chain_plug.find_relevant_transactions(chain);
2434 // Only calculate if there are relevant s-transactions
2435 if (!relevant_s_transactions.empty()) {
2436 ilog("Relevant S-Transactions found: ${count}", ("count", relevant_s_transactions.size()));
2437 // Step 2: Builds array of leaves in the same order as they appear in the transaction list.
2438 // Step 3: Computes a Merkle root hash: the S-Root.
2439 checksum256_type s_root = sub_chain_plug.calculate_s_root(relevant_s_transactions);
2440 ilog("s_root calculated: ${root}", ("root", s_root.str()));
2441 // Step 4: S-Root is hashed with the previous S-ID using SHA-256
2442 // Step 5: Takes the 32 least-significant bits from the previous S-ID to get the previous S-Block number, and increment to get the new S-Block number
2443 // Step 6: Hashes the S-Root with the previous S-ID with SHA-256, then replace the 32 least significant bits with the new S-Block number to produce the new S-ID
2444 checksum256_type curr_s_id = sub_chain_plug.compute_curr_s_id(s_root);
2445 ilog("curr_s_id calculated: ${curr_s_id}", ("curr_s_id", curr_s_id.str()));
2446 // Prepare the s_header for the current block to be added to the header extension
2447 s_header s_header {
2448 sub_chain_plug.get_contract_name(),
2449 sub_chain_plug.get_prev_s_id(),
2450 curr_s_id,
2451 s_root
2452 };
2453 ilog("S-Header prepared: ${s_header}", ("s_header", s_header.to_string()));
2454
2455 // Set the s_root in the chain controller for the building block state
2456 // to be referenced and passed to make_block_header on finalize_block below
2457 chain.set_s_header( s_header );
2458
2459 // Update the plugin's stored prev_s_id with the newly calculated S-ID
2460 sub_chain_plug.update_prev_s_id(curr_s_id);
2461 }
2462
2463 //idump( (fc::time_point::now() - chain.pending_block_time()) );
2464 chain.finalize_block( [&]( const digest_type& d ) {
2465 auto debug_logger = maybe_make_debug_time_logger();
2466 vector<signature_type> sigs;
2467 sigs.reserve(relevant_providers.size());
2468
2469 // sign with all relevant public keys
2470 for (const auto& p : relevant_providers) {
2471 sigs.emplace_back(p.get()(d));
2472 }
2473 return sigs;
2474 } );
2475
2476 chain.commit_block();
2477
2478 block_state_ptr new_bs = chain.head_block_state();
2479
2480 _account_fails.report();
2481 _account_fails.clear();
2482
2483 ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} [trxs: ${count}, lib: ${lib}, confirmed: ${confs}]",
2484 ("p",new_bs->header.producer)("id",new_bs->id.str().substr(8,16))
2485 ("n",new_bs->block_num)("t",new_bs->header.timestamp)
2486 ("count",new_bs->block->transactions.size())("lib",chain.last_irreversible_block_num())("confs", new_bs->header.confirmed));
2487
2488}
abstract_plugin & get_plugin(const string &name) const
std::vector< chain::digest_type > _protocol_features_to_activate
std::map< chain::public_key_type, signature_provider_type > _signature_providers
fc::crypto::public_key public_key_type
Definition types.hpp:76
checksum_type digest_type
Definition types.hpp:237
fc::sha256 checksum256_type
Definition types.hpp:233
static void for_each_key(const block_signing_authority &authority, Op &&op)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ production_disabled_by_policy()

bool sysio::producer_plugin_impl::production_disabled_by_policy ( )
inline

Definition at line 781 of file producer_plugin.cpp.

Here is the caller graph for this function:

◆ remove_expired_blacklisted_trxs()

bool sysio::producer_plugin_impl::remove_expired_blacklisted_trxs ( const fc::time_point & deadline)

Definition at line 1975 of file producer_plugin.cpp.

1976{
1977 bool exhausted = false;
1978 auto& blacklist_by_expiry = _blacklisted_transactions.get<by_expiry>();
1979 if(!blacklist_by_expiry.empty()) {
1980 const chain::controller& chain = chain_plug->chain();
1981 const auto lib_time = chain.last_irreversible_block_time();
1982
1983 int num_expired = 0;
1984 int orig_count = _blacklisted_transactions.size();
1985
1986 while (!blacklist_by_expiry.empty() && blacklist_by_expiry.begin()->expiry <= lib_time) {
1987 if ( should_interrupt_start_block( deadline ) ) {
1988 exhausted = true;
1989 break;
1990 }
1991 blacklist_by_expiry.erase(blacklist_by_expiry.begin());
1992 num_expired++;
1993 }
1994
1995 fc_dlog(_log, "Processed ${n} blacklisted transactions, Expired ${expired}",
1996 ("n", orig_count)("expired", num_expired));
1997 }
1998 return !exhausted;
1999}
time_point last_irreversible_block_time() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_expired_trxs()

bool sysio::producer_plugin_impl::remove_expired_trxs ( const fc::time_point & deadline)

Definition at line 1910 of file producer_plugin.cpp.

1911{
1912 chain::controller& chain = chain_plug->chain();
1913 auto pending_block_time = chain.pending_block_time();
1914
1915 // remove all expired transactions
1916 size_t num_expired_persistent = 0;
1917 size_t num_expired_other = 0;
1918 size_t orig_count = _unapplied_transactions.size();
1919 bool exhausted = !_unapplied_transactions.clear_expired( pending_block_time, [&](){ return should_interrupt_start_block( deadline ); },
1920 [chain_plug = chain_plug, &num_expired_persistent, &num_expired_other, pbm = _pending_block_mode,
1921 &chain, has_producers = !_producers.empty()]( const packed_transaction_ptr& packed_trx_ptr, trx_enum_type trx_type ) {
1922 if( trx_type == trx_enum_type::persisted ) {
1923 if( pbm == pending_block_mode::producing ) {
1925 "[TRX_TRACE] Block ${block_num} for producer ${prod} is EXPIRING PERSISTED tx: ${txid}",
1926 ("block_num", chain.head_block_num() + 1)("txid", packed_trx_ptr->id())
1927 ("prod", chain.is_building_block() ? chain.pending_block_producer() : name()) );
1928 fc_dlog(_trx_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is EXPIRING PERSISTED tx: ${trx}",
1929 ("block_num", chain.head_block_num() + 1)
1930 ("prod", chain.is_building_block() ? chain.pending_block_producer() : name())
1931 ("trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1932 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Block ${block_num} for producer ${prod} is EXPIRING PERSISTED tx: ${entire_trx}",
1933 ("block_num", chain.head_block_num() + 1)
1934 ("prod", chain.is_building_block() ? chain.pending_block_producer() : name())
1935 ("entire_trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1936
1937 } else {
1938 fc_dlog(_trx_failed_trace_log, "[TRX_TRACE] Speculative execution is EXPIRING PERSISTED tx: ${txid}", ("txid", packed_trx_ptr->id()));
1939
1940 fc_dlog(_trx_log, "[TRX_TRACE] Speculative execution is EXPIRING PERSISTED tx: ${trx}",
1941 ("trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1942 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Speculative execution is EXPIRING PERSISTED tx: ${entire_trx}",
1943 ("entire_trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1944 }
1945 ++num_expired_persistent;
1946 } else {
1947 if (has_producers) {
1949 "[TRX_TRACE] Node with producers configured is dropping an EXPIRED transaction that was PREVIOUSLY ACCEPTED : ${txid}",
1950 ("txid", packed_trx_ptr->id()));
1951
1952 fc_dlog(_trx_log, "[TRX_TRACE] Node with producers configured is dropping an EXPIRED transaction that was PREVIOUSLY ACCEPTED: ${trx}",
1953 ("trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1954 fc_dlog(_trx_trace_failure_log, "[TRX_TRACE] Node with producers configured is dropping an EXPIRED transaction that was PREVIOUSLY ACCEPTED: ${entire_trx}",
1955 ("entire_trx", chain_plug->get_log_trx(packed_trx_ptr->get_transaction())));
1956 }
1957 ++num_expired_other;
1958 }
1959 });
1960
1962 fc_wlog( _log, "Unable to process all expired transactions in unapplied queue before deadline, "
1963 "Persistent expired ${persistent_expired}, Other expired ${other_expired}",
1964 ("persistent_expired", num_expired_persistent)("other_expired", num_expired_other) );
1965 } else {
1966 fc_dlog( _log, "Processed ${m} expired transactions of the ${n} transactions in the unapplied queue, "
1967 "Persistent expired ${persistent_expired}, Other expired ${other_expired}",
1968 ("m", num_expired_persistent+num_expired_other)("n", orig_count)
1969 ("persistent_expired", num_expired_persistent)("other_expired", num_expired_other) );
1970 }
1971
1972 return !exhausted;
1973}
std::string name
time_point pending_block_time() const
bool clear_expired(const time_point &pending_block_time, Yield &&yield, Callback &&callback)
std::shared_ptr< const packed_transaction > packed_transaction_ptr
Here is the call graph for this function:
Here is the caller graph for this function:

◆ restart_speculative_block()

void sysio::producer_plugin_impl::restart_speculative_block ( )
inline

Definition at line 520 of file producer_plugin.cpp.

520 {
521 chain::controller& chain = chain_plug->chain();
522 // abort the pending block
523 _unapplied_transactions.add_aborted( chain.abort_block() );
524
526 }
Here is the call graph for this function:

◆ schedule_delayed_production_loop()

void sysio::producer_plugin_impl::schedule_delayed_production_loop ( const std::weak_ptr< producer_plugin_impl > & weak_this,
std::optional< fc::time_point > wake_up_time )

Definition at line 2356 of file producer_plugin.cpp.

2356 {
2357 if (wake_up_time) {
2358 fc_dlog(_log, "Scheduling Speculative/Production Change at ${time}", ("time", wake_up_time));
2359 static const boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1));
2360 _timer.expires_at(epoch + boost::posix_time::microseconds(wake_up_time->time_since_epoch().count()));
2361 _timer.async_wait( app().get_priority_queue().wrap( priority::high,
2362 [weak_this,cid=++_timer_corelation_id](const boost::system::error_code& ec) {
2363 auto self = weak_this.lock();
2364 if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) {
2365 self->schedule_production_loop();
2366 }
2367 } ) );
2368 }
2369}
static constexpr int high
Here is the call graph for this function:
Here is the caller graph for this function:

◆ schedule_maybe_produce_block()

void sysio::producer_plugin_impl::schedule_maybe_produce_block ( bool exhausted)

Definition at line 2298 of file producer_plugin.cpp.

2298 {
2299 chain::controller& chain = chain_plug->chain();
2300
2301 // we succeeded but block may be exhausted
2302 static const boost::posix_time::ptime epoch( boost::gregorian::date( 1970, 1, 1 ) );
2303 auto deadline = calculate_block_deadline( chain.pending_block_time() );
2304
2305 if( !exhausted && deadline > fc::time_point::now() ) {
2306 // ship this block off no later than its deadline
2307 SYS_ASSERT( chain.is_building_block(), missing_pending_block_state,
2308 "producing without pending_block_state, start_block succeeded" );
2309 _timer.expires_at( epoch + boost::posix_time::microseconds( deadline.time_since_epoch().count() ) );
2310 fc_dlog( _log, "Scheduling Block Production on Normal Block #${num} for ${time}",
2311 ("num", chain.head_block_num() + 1)( "time", deadline ) );
2312 } else {
2313 SYS_ASSERT( chain.is_building_block(), missing_pending_block_state, "producing without pending_block_state" );
2314 _timer.expires_from_now( boost::posix_time::microseconds( 0 ) );
2315 fc_dlog( _log, "Scheduling Block Production on ${desc} Block #${num} immediately",
2316 ("num", chain.head_block_num() + 1)("desc", block_is_exhausted() ? "Exhausted" : "Deadline exceeded") );
2317 }
2318
2319 _timer.async_wait( app().get_priority_queue().wrap( priority::high,
2320 [&chain, weak_this = weak_from_this(), cid=++_timer_corelation_id](const boost::system::error_code& ec) {
2321 auto self = weak_this.lock();
2322 if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) {
2323 // pending_block_state expected, but can't assert inside async_wait
2324 auto block_num = chain.is_building_block() ? chain.head_block_num() + 1 : 0;
2325 fc_dlog( _log, "Produce block timer for ${num} running at ${time}", ("num", block_num)("time", fc::time_point::now()) );
2326 auto res = self->maybe_produce_block();
2327 fc_dlog( _log, "Producing Block #${num} returned: ${res}", ("num", block_num)( "res", res ) );
2328 }
2329 } ) );
2330}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ schedule_production_loop()

void sysio::producer_plugin_impl::schedule_production_loop ( )

Definition at line 2255 of file producer_plugin.cpp.

2255 {
2256 _received_block = false;
2257 _timer.cancel();
2258
2259 auto result = start_block();
2260
2261 if (result == start_block_result::failed) {
2262 elog("Failed to start a pending block, will try again later");
2263 _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 ));
2264
2265 // we failed to start a block, so try again later?
2266 _timer.async_wait( app().get_priority_queue().wrap( priority::high,
2267 [weak_this = weak_from_this(), cid = ++_timer_corelation_id]( const boost::system::error_code& ec ) {
2268 auto self = weak_this.lock();
2269 if( self && ec != boost::asio::error::operation_aborted && cid == self->_timer_corelation_id ) {
2270 self->schedule_production_loop();
2271 }
2272 } ) );
2273 } else if (result == start_block_result::waiting_for_block){
2274 if (!_producers.empty() && !production_disabled_by_policy()) {
2275 fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change");
2277 } else {
2278 fc_dlog(_log, "Waiting till another block is received");
2279 // nothing to do until more blocks arrive
2280 }
2281
2282 } else if (result == start_block_result::waiting_for_production) {
2283 // scheduled in start_block()
2284
2287
2289 chain::controller& chain = chain_plug->chain();
2290 fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change");
2291 SYS_ASSERT( chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state" );
2292 schedule_delayed_production_loop(weak_from_this(), calculate_producer_wake_up_time(chain.pending_block_time()));
2293 } else {
2294 fc_dlog(_log, "Speculative Block Created");
2295 }
2296}
void schedule_delayed_production_loop(const std::weak_ptr< producer_plugin_impl > &weak_this, std::optional< fc::time_point > wake_up_time)
void schedule_maybe_produce_block(bool exhausted)
std::optional< fc::time_point > calculate_producer_wake_up_time(const block_timestamp_type &ref_block_time) const
start_block_result start_block()
std::atomic< bool > _received_block
fc::time_point calculate_pending_block_time() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ should_interrupt_start_block()

bool sysio::producer_plugin_impl::should_interrupt_start_block ( const fc::time_point & deadline) const
inline

Definition at line 1674 of file producer_plugin.cpp.

1674 {
1676 return deadline <= fc::time_point::now();
1677 }
1678 // if we can produce then honor deadline so production starts on time
1679 return (!_producers.empty() && deadline <= fc::time_point::now()) || _received_block;
1680}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_block()

producer_plugin_impl::start_block_result sysio::producer_plugin_impl::start_block ( )

Definition at line 1682 of file producer_plugin.cpp.

1682 {
1683 chain::controller& chain = chain_plug->chain();
1684
1687
1688 const auto& hbs = chain.head_block_state();
1689
1690 if( chain.get_terminate_at_block() > 0 && chain.get_terminate_at_block() < chain.head_block_num() ) {
1691 ilog("Reached configured maximum block ${num}; terminating", ("num", chain.get_terminate_at_block()));
1692 app().quit();
1694 }
1695
1696 const fc::time_point now = fc::time_point::now();
1697 const fc::time_point block_time = calculate_pending_block_time();
1698 const fc::time_point preprocess_deadline = calculate_block_deadline(block_time);
1699
1700 const pending_block_mode previous_pending_mode = _pending_block_mode;
1702
1703 // Not our turn
1704 const auto& scheduled_producer = hbs->get_scheduled_producer(block_time);
1705
1706 const auto current_watermark = get_watermark(scheduled_producer.producer_name);
1707
1708 size_t num_relevant_signatures = 0;
1709 scheduled_producer.for_each_key([&](const public_key_type& key){
1710 const auto& iter = _signature_providers.find(key);
1711 if(iter != _signature_providers.end()) {
1712 num_relevant_signatures++;
1713 }
1714 });
1715
1716 auto irreversible_block_age = get_irreversible_block_age();
1717
1718 // If the next block production opportunity is in the present or future, we're synced.
1719 if( !_production_enabled ) {
1721 } else if( _producers.find(scheduled_producer.producer_name) == _producers.end()) {
1723 } else if (num_relevant_signatures == 0) {
1724 elog("Not producing block because I don't have any private keys relevant to authority: ${authority}", ("authority", scheduled_producer.authority));
1726 } else if ( _pause_production ) {
1727 elog("Not producing block because production is explicitly paused");
1729 } else if ( _max_irreversible_block_age_us.count() >= 0 && irreversible_block_age >= _max_irreversible_block_age_us ) {
1730 elog("Not producing block because the irreversible block is too old [age:${age}s, max:${max}s]", ("age", irreversible_block_age.count() / 1'000'000)( "max", _max_irreversible_block_age_us.count() / 1'000'000 ));
1732 }
1733
1735 // determine if our watermark excludes us from producing at this point
1736 if (current_watermark) {
1737 const block_timestamp_type block_timestamp{block_time};
1738 if (current_watermark->first > hbs->block_num) {
1739 elog("Not producing block because \"${producer}\" signed a block at a higher block number (${watermark}) than the current fork's head (${head_block_num})",
1740 ("producer", scheduled_producer.producer_name)
1741 ("watermark", current_watermark->first)
1742 ("head_block_num", hbs->block_num));
1744 } else if (current_watermark->second >= block_timestamp) {
1745 elog("Not producing block because \"${producer}\" signed a block at the next block time or later (${watermark}) than the pending block time (${block_timestamp})",
1746 ("producer", scheduled_producer.producer_name)
1747 ("watermark", current_watermark->second)
1748 ("block_timestamp", block_timestamp));
1750 }
1751 }
1752 }
1753
1755 auto head_block_age = now - chain.head_block_time();
1756 if (head_block_age > fc::seconds(5))
1758 }
1759
1761 const auto start_block_time = block_time - fc::microseconds( config::block_interval_us );
1762 if( now < start_block_time ) {
1763 fc_dlog(_log, "Not producing block waiting for production window ${n} ${bt}", ("n", hbs->block_num + 1)("bt", block_time) );
1764 // start_block_time instead of block_time because schedule_delayed_production_loop calculates next block time from given time
1765 schedule_delayed_production_loop(weak_from_this(), calculate_producer_wake_up_time(start_block_time));
1767 }
1768 } else if (previous_pending_mode == pending_block_mode::producing) {
1769 // just produced our last block of our round
1770 const auto start_block_time = block_time - fc::microseconds( config::block_interval_us );
1771 fc_dlog(_log, "Not starting speculative block until ${bt}", ("bt", start_block_time) );
1772 schedule_delayed_production_loop( weak_from_this(), start_block_time);
1774 }
1775
1776 fc_dlog(_log, "Starting block #${n} at ${time} producer ${p}",
1777 ("n", hbs->block_num + 1)("time", now)("p", scheduled_producer.producer_name));
1778
1779 try {
1780 uint16_t blocks_to_confirm = 0;
1781
1783 // determine how many blocks this producer can confirm
1784 // 1) if it is not a producer from this node, assume no confirmations (we will discard this block anyway)
1785 // 2) if it is a producer on this node that has never produced, the conservative approach is to assume no
1786 // confirmations to make sure we don't double sign after a crash TODO: make these watermarks durable?
1787 // 3) if it is a producer on this node where this node knows the last block it produced, safely set it -UNLESS-
1788 // 4) the producer on this node's last watermark is higher (meaning on a different fork)
1789 if (current_watermark) {
1790 auto watermark_bn = current_watermark->first;
1791 if (watermark_bn < hbs->block_num) {
1792 blocks_to_confirm = (uint16_t)(std::min<uint32_t>(std::numeric_limits<uint16_t>::max(), (uint32_t)(hbs->block_num - watermark_bn)));
1793 }
1794 }
1795
1796 // can not confirm irreversible blocks
1797 blocks_to_confirm = (uint16_t)(std::min<uint32_t>(blocks_to_confirm, (uint32_t)(hbs->block_num - hbs->dpos_irreversible_blocknum)));
1798 }
1799
1800 abort_block();
1801
1802 auto features_to_activate = chain.get_preactivated_protocol_features();
1804 bool drop_features_to_activate = false;
1805 try {
1806 chain.validate_protocol_features( _protocol_features_to_activate );
1807 } catch ( const std::bad_alloc& ) {
1809 } catch ( const boost::interprocess::bad_alloc& ) {
1811 } catch( const fc::exception& e ) {
1812 wlog( "protocol features to activate are no longer all valid: ${details}",
1813 ("details",e.to_detail_string()) );
1814 drop_features_to_activate = true;
1815 } catch( const std::exception& e ) {
1816 wlog( "protocol features to activate are no longer all valid: ${details}",
1817 ("details",fc::std_exception_wrapper::from_current_exception(e).to_detail_string()) );
1818 drop_features_to_activate = true;
1819 }
1820
1821 if( drop_features_to_activate ) {
1823 } else {
1824 auto protocol_features_to_activate = _protocol_features_to_activate; // do a copy as pending_block might be aborted
1825 if( features_to_activate.size() > 0 ) {
1826 protocol_features_to_activate.reserve( protocol_features_to_activate.size()
1827 + features_to_activate.size() );
1828 std::set<digest_type> set_of_features_to_activate( protocol_features_to_activate.begin(),
1829 protocol_features_to_activate.end() );
1830 for( const auto& f : features_to_activate ) {
1831 auto res = set_of_features_to_activate.insert( f );
1832 if( res.second ) {
1833 protocol_features_to_activate.push_back( f );
1834 }
1835 }
1836 features_to_activate.clear();
1837 }
1838 std::swap( features_to_activate, protocol_features_to_activate );
1840 ilog( "signaling activation of the following protocol features in block ${num}: ${features_to_activate}",
1841 ("num", hbs->block_num + 1)("features_to_activate", features_to_activate) );
1842 }
1843 }
1844
1845 chain.start_block( block_time, blocks_to_confirm, features_to_activate, preprocess_deadline );
1846 } LOG_AND_DROP();
1847
1848 if( chain.is_building_block() ) {
1849 const auto& pending_block_signing_authority = chain.pending_block_signing_authority();
1850
1851 if (_pending_block_mode == pending_block_mode::producing && pending_block_signing_authority != scheduled_producer.authority) {
1852 elog("Unexpected block signing authority, reverting to speculative mode! [expected: \"${expected}\", actual: \"${actual\"", ("expected", scheduled_producer.authority)("actual", pending_block_signing_authority));
1854 }
1855
1856 try {
1857 _account_fails.clear();
1858
1859 if( !remove_expired_trxs( preprocess_deadline ) )
1861 if( !remove_expired_blacklisted_trxs( preprocess_deadline ) )
1863 if( !_subjective_billing.remove_expired( _log, chain.pending_block_time(), fc::time_point::now(),
1864 [&](){ return should_interrupt_start_block( preprocess_deadline ); } ) ) {
1866 }
1867
1868 // limit execution of pending incoming to once per block
1869 size_t pending_incoming_process_limit = _unapplied_transactions.incoming_size();
1870
1871 if( !process_unapplied_trxs( preprocess_deadline ) )
1873
1875 auto scheduled_trx_deadline = preprocess_deadline;
1877 scheduled_trx_deadline = std::min<fc::time_point>(
1878 scheduled_trx_deadline,
1880 );
1881 }
1882 // may exhaust scheduled_trx_deadline but not preprocess_deadline, exhausted preprocess_deadline checked below
1883 process_scheduled_and_incoming_trxs( scheduled_trx_deadline, pending_incoming_process_limit );
1884 }
1885
1886 if( app().is_quiting() ) // db guard exception above in LOG_AND_DROP could have called app().quit()
1888 if ( should_interrupt_start_block( preprocess_deadline ) || block_is_exhausted() ) {
1890 } else {
1891 if( !process_incoming_trxs( preprocess_deadline, pending_incoming_process_limit ) )
1894 }
1895
1896 } catch ( const guard_exception& e ) {
1899 } catch ( std::bad_alloc& ) {
1901 } catch ( boost::interprocess::bad_alloc& ) {
1903 }
1904
1905 }
1906
1908}
std::string to_detail_string(log_level ll=log_level::all) const
bool accept_transactions() const
bool remove_expired_trxs(const fc::time_point &deadline)
bool remove_expired_blacklisted_trxs(const fc::time_point &deadline)
bool process_incoming_trxs(const fc::time_point &deadline, size_t &pending_incoming_process_limit)
bool process_unapplied_trxs(const fc::time_point &deadline)
void process_scheduled_and_incoming_trxs(const fc::time_point &deadline, size_t &pending_incoming_process_limit)
bool remove_expired(fc::logger &log, const fc::time_point &pending_block_time, const fc::time_point &now, Yield &&yield)
#define wlog(FORMAT,...)
Definition logger.hpp:124
void swap(picojson::value &x, picojson::value &y)
unsigned short uint16_t
Definition stdint.h:125
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ _accepted_block_connection

std::optional<scoped_connection> sysio::producer_plugin_impl::_accepted_block_connection

Definition at line 355 of file producer_plugin.cpp.

◆ _accepted_block_header_connection

std::optional<scoped_connection> sysio::producer_plugin_impl::_accepted_block_header_connection

Definition at line 356 of file producer_plugin.cpp.

◆ _account_fails

account_failures sysio::producer_plugin_impl::_account_fails {_subjective_billing}

Definition at line 353 of file producer_plugin.cpp.

◆ _blacklisted_transactions

transaction_id_with_expiry_index sysio::producer_plugin_impl::_blacklisted_transactions

Definition at line 350 of file producer_plugin.cpp.

◆ _disable_persist_until_expired

bool sysio::producer_plugin_impl::_disable_persist_until_expired = false

Definition at line 334 of file producer_plugin.cpp.

◆ _disable_subjective_api_billing

bool sysio::producer_plugin_impl::_disable_subjective_api_billing = true

Definition at line 336 of file producer_plugin.cpp.

◆ _disable_subjective_p2p_billing

bool sysio::producer_plugin_impl::_disable_subjective_p2p_billing = true

Definition at line 335 of file producer_plugin.cpp.

◆ _incoming_block_sync_provider

incoming::methods::block_sync::method_type::handle sysio::producer_plugin_impl::_incoming_block_sync_provider

Definition at line 347 of file producer_plugin.cpp.

◆ _incoming_defer_ratio

double sysio::producer_plugin_impl::_incoming_defer_ratio = 1.0

Definition at line 372 of file producer_plugin.cpp.

◆ _incoming_transaction_async_provider

incoming::methods::transaction_async::method_type::handle sysio::producer_plugin_impl::_incoming_transaction_async_provider

Definition at line 348 of file producer_plugin.cpp.

◆ _irreversible_block_connection

std::optional<scoped_connection> sysio::producer_plugin_impl::_irreversible_block_connection

Definition at line 357 of file producer_plugin.cpp.

◆ _irreversible_block_time

fc::time_point sysio::producer_plugin_impl::_irreversible_block_time

Definition at line 337 of file producer_plugin.cpp.

◆ _kiod_provider_timeout_us

fc::microseconds sysio::producer_plugin_impl::_kiod_provider_timeout_us

Definition at line 338 of file producer_plugin.cpp.

◆ _last_block_time_offset_us

int32_t sysio::producer_plugin_impl::_last_block_time_offset_us = 0

Definition at line 330 of file producer_plugin.cpp.

◆ _max_block_cpu_usage_threshold_us

uint32_t sysio::producer_plugin_impl::_max_block_cpu_usage_threshold_us = 0

Definition at line 331 of file producer_plugin.cpp.

◆ _max_block_net_usage_threshold_bytes

uint32_t sysio::producer_plugin_impl::_max_block_net_usage_threshold_bytes = 0

Definition at line 332 of file producer_plugin.cpp.

◆ _max_irreversible_block_age_us

fc::microseconds sysio::producer_plugin_impl::_max_irreversible_block_age_us

Definition at line 328 of file producer_plugin.cpp.

◆ _max_scheduled_transaction_time_per_block_ms

int32_t sysio::producer_plugin_impl::_max_scheduled_transaction_time_per_block_ms = 0

Definition at line 333 of file producer_plugin.cpp.

◆ _max_transaction_time_ms

std::atomic<int32_t> sysio::producer_plugin_impl::_max_transaction_time_ms

Definition at line 326 of file producer_plugin.cpp.

◆ _options

boost::program_options::variables_map sysio::producer_plugin_impl::_options

Definition at line 312 of file producer_plugin.cpp.

◆ _pause_production

bool sysio::producer_plugin_impl::_pause_production = false

Definition at line 314 of file producer_plugin.cpp.

◆ _pending_block_mode

pending_block_mode sysio::producer_plugin_impl::_pending_block_mode = pending_block_mode::speculating

Definition at line 322 of file producer_plugin.cpp.

◆ _pending_snapshot_index

pending_snapshot_index sysio::producer_plugin_impl::_pending_snapshot_index

Definition at line 351 of file producer_plugin.cpp.

◆ _produce_time_offset_us

int32_t sysio::producer_plugin_impl::_produce_time_offset_us = 0

Definition at line 329 of file producer_plugin.cpp.

◆ _producer_watermarks

std::map<chain::account_name, producer_watermark> sysio::producer_plugin_impl::_producer_watermarks

Definition at line 321 of file producer_plugin.cpp.

◆ _producers

std::set<chain::account_name> sysio::producer_plugin_impl::_producers

Definition at line 318 of file producer_plugin.cpp.

◆ _production_enabled

bool sysio::producer_plugin_impl::_production_enabled = false

Definition at line 313 of file producer_plugin.cpp.

◆ _protocol_features_signaled

bool sysio::producer_plugin_impl::_protocol_features_signaled = false

Definition at line 341 of file producer_plugin.cpp.

◆ _protocol_features_to_activate

std::vector<chain::digest_type> sysio::producer_plugin_impl::_protocol_features_to_activate

Definition at line 340 of file producer_plugin.cpp.

◆ _received_block

std::atomic<bool> sysio::producer_plugin_impl::_received_block {false}

Definition at line 327 of file producer_plugin.cpp.

327{false}; // modified by net_plugin thread pool and app thread

◆ _signature_providers

std::map<chain::public_key_type, signature_provider_type> sysio::producer_plugin_impl::_signature_providers

Definition at line 317 of file producer_plugin.cpp.

◆ _snapshots_dir

bfs::path sysio::producer_plugin_impl::_snapshots_dir

Definition at line 375 of file producer_plugin.cpp.

◆ _subjective_billing

subjective_billing sysio::producer_plugin_impl::_subjective_billing

Definition at line 352 of file producer_plugin.cpp.

◆ _thread_pool

std::optional<named_thread_pool> sysio::producer_plugin_impl::_thread_pool

Definition at line 324 of file producer_plugin.cpp.

◆ _timer

boost::asio::deadline_timer sysio::producer_plugin_impl::_timer

Definition at line 319 of file producer_plugin.cpp.

◆ _timer_corelation_id

uint32_t sysio::producer_plugin_impl::_timer_corelation_id = 0

Definition at line 369 of file producer_plugin.cpp.

◆ _transaction_ack_channel

compat::channels::transaction_ack::channel_type& sysio::producer_plugin_impl::_transaction_ack_channel

Definition at line 345 of file producer_plugin.cpp.

◆ _unapplied_transactions

unapplied_transaction_queue sysio::producer_plugin_impl::_unapplied_transactions

Definition at line 323 of file producer_plugin.cpp.

◆ chain_plug

chain_plugin* sysio::producer_plugin_impl::chain_plug = nullptr

Definition at line 343 of file producer_plugin.cpp.


The documentation for this class was generated from the following file: