Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain::controller_impl Struct Reference
Collaboration diagram for sysio::chain::controller_impl:

Classes

struct  reset_new_handler
 

Public Types

typedef pair< scope_name, action_namehandler_key
 

Public Member Functions

void pop_block ()
 
template<builtin_protocol_feature_t F>
void on_activation ()
 
template<builtin_protocol_feature_t F>
void set_activation_handler ()
 
void trigger_activation_handler (builtin_protocol_feature_t f)
 
void set_apply_handler (account_name receiver, account_name contract, action_name action, apply_handler v)
 
 controller_impl (const controller::config &cfg, controller &s, protocol_feature_set &&pfs, const chain_id_type &chain_id)
 
template<typename Signal , typename Arg >
void emit (const Signal &s, Arg &&a)
 
void dmlog_applied_transaction (const transaction_trace_ptr &t)
 
void log_irreversible ()
 
void initialize_blockchain_state (const genesis_state &genesis)
 
void replay (std::function< bool()> check_shutdown)
 
void startup (std::function< void()> shutdown, std::function< bool()> check_shutdown, const snapshot_reader_ptr &snapshot)
 
void startup (std::function< void()> shutdown, std::function< bool()> check_shutdown, const genesis_state &genesis)
 
void startup (std::function< void()> shutdown, std::function< bool()> check_shutdown)
 
void init (std::function< bool()> check_shutdown)
 
 ~controller_impl ()
 
void add_indices ()
 
void clear_all_undo ()
 
void add_contract_tables_to_snapshot (const snapshot_writer_ptr &snapshot) const
 
void read_contract_tables_from_snapshot (const snapshot_reader_ptr &snapshot)
 
void add_to_snapshot (const snapshot_writer_ptr &snapshot)
 
void read_from_snapshot (const snapshot_reader_ptr &snapshot, uint32_t blog_start, uint32_t blog_end)
 
sha256 calculate_integrity_hash ()
 
void create_native_account (const fc::time_point &initial_timestamp, account_name name, const authority &owner, const authority &active, bool is_privileged=false)
 
void initialize_database (const genesis_state &genesis)
 
fc::scoped_exit< std::function< void()> > make_block_restore_point ()
 
transaction_trace_ptr apply_onerror (const generated_transaction &gtrx, fc::time_point block_deadline, fc::microseconds max_transaction_time, fc::time_point start, uint32_t &cpu_time_to_bill_us, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time=false, bool enforce_whiteblacklist=true)
 
int64_t remove_scheduled_transaction (const generated_transaction_object &gto)
 
bool failure_is_subjective (const fc::exception &e) const
 
bool scheduled_failure_is_subjective (const fc::exception &e) const
 
transaction_trace_ptr push_scheduled_transaction (const transaction_id_type &trxid, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time=false)
 
transaction_trace_ptr push_scheduled_transaction (const generated_transaction_object &gto, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time=false)
 
template<typename T >
const transaction_receiptpush_receipt (const T &trx, transaction_receipt_header::status_enum status, uint64_t cpu_usage_us, uint64_t net_usage)
 push_scheduled_transaction
 
transaction_trace_ptr push_transaction (const transaction_metadata_ptr &trx, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time, int64_t subjective_cpu_bill_us)
 
void start_block (block_timestamp_type when, uint16_t confirm_block_count, const vector< digest_type > &new_protocol_feature_activations, controller::block_status s, const std::optional< block_id_type > &producer_block_id, const fc::time_point &deadline)
 push_transaction
 
void finalize_block ()
 start_block
 
void commit_block (bool add_to_fork_db)
 finalize_block
 
void check_protocol_features (block_timestamp_type timestamp, const flat_set< digest_type > &currently_activated_protocol_features, const vector< digest_type > &new_protocol_features)
 
void report_block_header_diff (const block_header &b, const block_header &ab)
 
void apply_block (const block_state_ptr &bsp, controller::block_status s, const trx_meta_cache_lookup &trx_lookup)
 
block_state_ptr create_block_state_i (const block_id_type &id, const signed_block_ptr &b, const block_header_state &prev)
 apply_block
 
std::future< block_state_ptrcreate_block_state_future (const block_id_type &id, const signed_block_ptr &b)
 
block_state_ptr create_block_state (const block_id_type &id, const signed_block_ptr &b)
 
void push_block (const block_state_ptr &bsp, const forked_branch_callback &forked_branch_cb, const trx_meta_cache_lookup &trx_lookup)
 
void replay_push_block (const signed_block_ptr &b, controller::block_status s)
 
void maybe_switch_forks (const block_state_ptr &new_head, controller::block_status s, const forked_branch_callback &forked_branch_cb, const trx_meta_cache_lookup &trx_lookup)
 
vector< transaction_metadata_ptrabort_block ()
 push_block
 
void update_producers_authority ()
 
void create_block_summary (const block_id_type &id)
 
void clear_expired_input_transactions (const fc::time_point &deadline)
 
bool sender_avoids_whitelist_blacklist_enforcement (account_name sender) const
 
void check_actor_list (const flat_set< account_name > &actors) const
 
void check_contract_list (account_name code) const
 
void check_action_list (account_name code, action_name action) const
 
void check_key_list (const public_key_type &key) const
 
signed_transaction get_on_block_transaction ()
 
deep_mind_handlerget_deep_mind_logger () const
 
uint32_t earliest_available_block_num () const
 

Static Public Member Functions

static auto validate_db_version (const chainbase::database &db)
 
static std::optional< genesis_stateextract_legacy_genesis_state (snapshot_reader &snapshot, uint32_t version)
 
static checksum256_type calculate_trx_merkle (const vector< transaction_receipt > &trxs)
 

Public Attributes

reset_new_handler rnh
 
controllerself
 
std::function< void()> shutdown
 
chainbase::database db
 
block_log blog
 
std::optional< pending_statepending
 
block_state_ptr head
 
fork_database fork_db
 
wasm_interface wasmif
 
resource_limits_manager resource_limits
 
authorization_manager authorization
 
protocol_feature_manager protocol_features
 
controller::config conf
 
const chain_id_type chain_id
 
bool replaying = false
 
db_read_mode read_mode = db_read_mode::SPECULATIVE
 
bool in_trx_requiring_checks = false
 if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
 
std::optional< fc::microsecondssubjective_cpu_leeway
 
bool trusted_producer_light_validation = false
 
uint32_t snapshot_head_block = 0
 
named_thread_pool thread_pool
 
platform_timer timer
 
deep_mind_handlerdeep_mind_logger = nullptr
 
map< account_name, map< handler_key, apply_handler > > apply_handlers
 
unordered_map< builtin_protocol_feature_t, std::function< void(controller_impl &)>, enum_hash< builtin_protocol_feature_t > > protocol_feature_activation_handlers
 

Detailed Description

Definition at line 220 of file controller.cpp.

Member Typedef Documentation

◆ handler_key

Constructor & Destructor Documentation

◆ controller_impl()

sysio::chain::controller_impl::controller_impl ( const controller::config & cfg,
controller & s,
protocol_feature_set && pfs,
const chain_id_type & chain_id )
inline

Definition at line 297 of file controller.cpp.

298 :rnh(),
299 self(s),
300 db( cfg.state_dir,
302 cfg.state_size, false, cfg.db_map_mode ),
303 blog( cfg.blocks_dir, cfg.prune_config ),
304 fork_db( cfg.blocks_dir / config::reversible_blocks_dir_name ),
305 wasmif( cfg.wasm_runtime, cfg.eosvmoc_tierup, db, cfg.state_dir, cfg.eosvmoc_config, !cfg.profile_accounts.empty() ),
306 resource_limits( db, [&s]() { return s.get_deep_mind_logger(); }),
307 authorization( s, db ),
308 protocol_features( std::move(pfs), [&s]() { return s.get_deep_mind_logger(); } ),
309 conf( cfg ),
311 read_mode( cfg.read_mode ),
312 thread_pool( "chain", cfg.thread_pool_size )
313 {
314 fork_db.open( [this]( block_timestamp_type timestamp,
315 const flat_set<digest_type>& cur_features,
316 const vector<digest_type>& new_features )
317 { check_protocol_features( timestamp, cur_features, new_features ); }
318 );
319
332
333 self.irreversible_block.connect([this](const block_state_ptr& bsp) {
334 wasmif.current_lib(bsp->block_num);
335 });
336
337
338#define SET_APP_HANDLER( receiver, contract, action) \
339 set_apply_handler( account_name(#receiver), account_name(#contract), action_name(#action), \
340 &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )
341
342 SET_APP_HANDLER( sysio, sysio, newaccount );
343 SET_APP_HANDLER( sysio, sysio, setcode );
344 SET_APP_HANDLER( sysio, sysio, setabi );
345 SET_APP_HANDLER( sysio, sysio, updateauth );
346 SET_APP_HANDLER( sysio, sysio, deleteauth );
347 SET_APP_HANDLER( sysio, sysio, linkauth );
348 SET_APP_HANDLER( sysio, sysio, unlinkauth );
349/*
350 SET_APP_HANDLER( sysio, sysio, postrecovery );
351 SET_APP_HANDLER( sysio, sysio, passrecovery );
352 SET_APP_HANDLER( sysio, sysio, vetorecovery );
353*/
354
355 SET_APP_HANDLER( sysio, sysio, canceldelay );
356 }
signal< void(const block_state_ptr &)> irreversible_block
void open(const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> &validator)
void current_lib(const uint32_t lib)
#define SET_APP_HANDLER(receiver, contract, action)
block_timestamp< config::block_interval_ms, config::block_timestamp_epoch > block_timestamp_type
std::shared_ptr< block_state > block_state_ptr
protocol_feature_manager protocol_features
const chain_id_type chain_id
resource_limits_manager resource_limits
named_thread_pool thread_pool
authorization_manager authorization
void check_protocol_features(block_timestamp_type timestamp, const flat_set< digest_type > &currently_activated_protocol_features, const vector< digest_type > &new_protocol_features)
char * s

◆ ~controller_impl()

sysio::chain::controller_impl::~controller_impl ( )
inline

Definition at line 724 of file controller.cpp.

724 {
726 pending.reset();
727 }
std::optional< pending_state > pending
Here is the call graph for this function:

Member Function Documentation

◆ abort_block()

vector< transaction_metadata_ptr > sysio::chain::controller_impl::abort_block ( )
inline

Definition at line 2315 of file controller.cpp.

2315 {
2316 vector<transaction_metadata_ptr> applied_trxs;
2317 if( pending ) {
2318 applied_trxs = pending->extract_trx_metas();
2319 pending.reset();
2321 }
2322 return applied_trxs;
2323 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_contract_tables_to_snapshot()

void sysio::chain::controller_impl::add_contract_tables_to_snapshot ( const snapshot_writer_ptr & snapshot) const
inline

Definition at line 747 of file controller.cpp.

747 {
748 snapshot->write_section("contract_tables", [this]( auto& section ) {
749 index_utils<table_id_multi_index>::walk(db, [this, &section]( const table_id_object& table_row ){
750 // add a row for the table
751 section.add_row(table_row, db);
752
753 // followed by a size row and then N data rows for each type of table
754 contract_database_index_set::walk_indices([this, &section, &table_row]( auto utils ) {
755 using utils_t = decltype(utils);
756 using value_t = typename decltype(utils)::index_t::value_type;
757 using by_table_id = object_to_table_id_tag_t<value_t>;
758
759 auto tid_key = boost::make_tuple(table_row.id);
760 auto next_tid_key = boost::make_tuple(table_id_object::id_type(table_row.id._id + 1));
761
762 unsigned_int size = utils_t::template size_range<by_table_id>(db, tid_key, next_tid_key);
763 section.add_row(size, db);
764
765 utils_t::template walk_range<by_table_id>(db, tid_key, next_tid_key, [this, &section]( const auto &row ) {
766 section.add_row(row, db);
767 });
768 });
769 });
770 });
771 }
static void walk(const chainbase::database &db, F function)
typename object_to_table_id_tag< T >::tag_type object_to_table_id_tag_t
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_indices()

void sysio::chain::controller_impl::add_indices ( )
inline

Definition at line 729 of file controller.cpp.

729 {
730 controller_index_set::add_indices(db);
731 contract_database_index_set::add_indices(db);
732
735 }
Here is the call graph for this function:

◆ add_to_snapshot()

void sysio::chain::controller_impl::add_to_snapshot ( const snapshot_writer_ptr & snapshot)
inline

Definition at line 802 of file controller.cpp.

802 {
803 // clear in case the previous call to clear did not finish in time of deadline
805
806 snapshot->write_section<chain_snapshot_header>([this]( auto &section ){
807 section.add_row(chain_snapshot_header(), db);
808 });
809
810 snapshot->write_section<block_state>([this]( auto &section ){
811 section.template add_row<block_header_state>(*head, db);
812 });
813
814 controller_index_set::walk_indices([this, &snapshot]( auto utils ){
815 using value_t = typename decltype(utils)::index_t::value_type;
816
817 // skip the table_id_object as its inlined with contract tables section
818 if (std::is_same<value_t, table_id_object>::value) {
819 return;
820 }
821
822 // skip the database_header as it is only relevant to in-memory database
823 if (std::is_same<value_t, database_header_object>::value) {
824 return;
825 }
826
827 snapshot->write_section<value_t>([this]( auto& section ){
828 decltype(utils)::walk(db, [this, &section]( const auto &row ) {
829 section.add_row(row, db);
830 });
831 });
832 });
833
835
838 }
static constexpr time_point maximum()
Definition time.hpp:46
void add_to_snapshot(const snapshot_writer_ptr &snapshot) const
void add_to_snapshot(const snapshot_writer_ptr &snapshot) const
void clear_expired_input_transactions(const fc::time_point &deadline)
void add_contract_tables_to_snapshot(const snapshot_writer_ptr &snapshot) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_block()

void sysio::chain::controller_impl::apply_block ( const block_state_ptr & bsp,
controller::block_status s,
const trx_meta_cache_lookup & trx_lookup )
inline

Definition at line 1948 of file controller.cpp.

1949 { try {
1950 try {
1951 const signed_block_ptr& b = bsp->block;
1952 const auto& new_protocol_feature_activations = bsp->get_new_protocol_feature_activations();
1953
1954 auto producer_block_id = bsp->id;
1955 start_block( b->timestamp, b->confirmed, new_protocol_feature_activations, s, producer_block_id, fc::time_point::maximum() );
1956
1957 const bool existing_trxs_metas = !bsp->trxs_metas().empty();
1958 const bool pub_keys_recovered = bsp->is_pub_keys_recovered();
1959 const bool skip_auth_checks = self.skip_auth_check();
1960 std::vector<std::tuple<transaction_metadata_ptr, recover_keys_future>> trx_metas;
1961 bool use_bsp_cached = false;
1962 if( pub_keys_recovered || (skip_auth_checks && existing_trxs_metas) ) {
1963 use_bsp_cached = true;
1964 } else {
1965 trx_metas.reserve( b->transactions.size() );
1966 for( const auto& receipt : b->transactions ) {
1967 if( std::holds_alternative<packed_transaction>(receipt.trx)) {
1968 const auto& pt = std::get<packed_transaction>(receipt.trx);
1969 transaction_metadata_ptr trx_meta_ptr = trx_lookup ? trx_lookup( pt.id() ) : transaction_metadata_ptr{};
1970 if( trx_meta_ptr && *trx_meta_ptr->packed_trx() != pt ) trx_meta_ptr = nullptr;
1971 if( trx_meta_ptr && ( skip_auth_checks || !trx_meta_ptr->recovered_keys().empty() ) ) {
1972 trx_metas.emplace_back( std::move( trx_meta_ptr ), recover_keys_future{} );
1973 } else if( skip_auth_checks ) {
1974 packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr
1975 trx_metas.emplace_back(
1978 } else {
1979 packed_transaction_ptr ptrx( b, &pt ); // alias signed_block_ptr
1982 trx_metas.emplace_back( transaction_metadata_ptr{}, std::move( fut ) );
1983 }
1984 }
1985 }
1986 }
1987
1989
1990 size_t packed_idx = 0;
1991 for( const auto& receipt : b->transactions ) {
1992 const auto& trx_receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
1993 auto num_pending_receipts = trx_receipts.size();
1994 if( std::holds_alternative<packed_transaction>(receipt.trx) ) {
1995 const auto& trx_meta = ( use_bsp_cached ? bsp->trxs_metas().at( packed_idx )
1996 : ( !!std::get<0>( trx_metas.at( packed_idx ) ) ?
1997 std::get<0>( trx_metas.at( packed_idx ) )
1998 : std::get<1>( trx_metas.at( packed_idx ) ).get() ) );
1999 trace = push_transaction( trx_meta, fc::time_point::maximum(), fc::microseconds::maximum(), receipt.cpu_usage_us, true, 0 );
2000 ++packed_idx;
2001 } else if( std::holds_alternative<transaction_id_type>(receipt.trx) ) {
2002 trace = push_scheduled_transaction( std::get<transaction_id_type>(receipt.trx), fc::time_point::maximum(), fc::microseconds::maximum(), receipt.cpu_usage_us, true );
2003 } else {
2004 SYS_ASSERT( false, block_validate_exception, "encountered unexpected receipt type" );
2005 }
2006
2007 bool transaction_failed = trace && trace->except;
2008 bool transaction_can_fail = receipt.status == transaction_receipt_header::hard_fail && std::holds_alternative<transaction_id_type>(receipt.trx);
2009 if( transaction_failed && !transaction_can_fail) {
2010 edump((*trace));
2011 throw *trace->except;
2012 }
2013
2014 SYS_ASSERT( trx_receipts.size() > 0,
2015 block_validate_exception, "expected a receipt, block_num ${bn}, block_id ${id}, receipt ${e}",
2016 ("bn", b->block_num())("id", producer_block_id)("e", receipt)
2017 );
2018 SYS_ASSERT( trx_receipts.size() == num_pending_receipts + 1,
2019 block_validate_exception, "expected receipt was not added, block_num ${bn}, block_id ${id}, receipt ${e}",
2020 ("bn", b->block_num())("id", producer_block_id)("e", receipt)
2021 );
2022 const transaction_receipt_header& r = trx_receipts.back();
2023 SYS_ASSERT( r == static_cast<const transaction_receipt_header&>(receipt),
2024 block_validate_exception, "receipt does not match, ${lhs} != ${rhs}",
2025 ("lhs", r)("rhs", static_cast<const transaction_receipt_header&>(receipt)) );
2026 }
2027
2028 // validated in create_block_state_future()
2029 std::get<building_block>(pending->_block_stage)._transaction_mroot = b->transaction_mroot;
2030
2031 // New: Process the s_header from block header extensions
2032 auto s_header_it = std::find_if(b->header_extensions.begin(), b->header_extensions.end(),
2033 [](const auto& ext) { return ext.first == s_root_extension::extension_id(); });
2034 if (s_header_it != b->header_extensions.end()) {
2035 ilog("Found s_root_extension in header_extensions, attempting to extract...");
2036 s_header extracted_s_header = fc::raw::unpack<s_header>(s_header_it->second);
2037 ilog("Extracted s_header: ${s_header}", ("s_header", extracted_s_header.to_string()));
2038 self.set_s_header(extracted_s_header); // Attempt to set s-header
2039 }
2040
2042
2043 auto& ab = std::get<assembled_block>(pending->_block_stage);
2044
2045
2046
2047 if( producer_block_id != ab._id ) {
2048 elog( "Validation block id does not match producer block id" );
2049 report_block_header_diff( *b, *ab._unsigned_block );
2050 // this implicitly asserts that all header fields (less the signature) are identical
2051 SYS_ASSERT( producer_block_id == ab._id, block_validate_exception, "Block ID does not match",
2052 ("producer_block_id", producer_block_id)("validator_block_id", ab._id) );
2053 }
2054
2055 if( !use_bsp_cached ) {
2056 bsp->set_trxs_metas( std::move( ab._trx_metas ), !skip_auth_checks );
2057 }
2058 // create completed_block with the existing block_state as we just verified it is the same as assembled_block
2059 pending->_block_stage = completed_block{ bsp };
2060
2061 commit_block(false);
2062 return;
2063 } catch ( const std::bad_alloc& ) {
2064 throw;
2065 } catch ( const boost::interprocess::bad_alloc& ) {
2066 throw;
2067 } catch ( const fc::exception& e ) {
2068 edump((e.to_detail_string()));
2069 abort_block();
2070 throw;
2071 } catch ( const std::exception& e ) {
2072 edump((e.what()));
2073 abort_block();
2074 throw;
2075 }
const mie::Vuint & r
Definition bn.cpp:28
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
std::string to_detail_string(log_level ll=log_level::all) const
static constexpr microseconds maximum()
Definition time.hpp:14
void set_s_header(const s_header &)
boost::asio::io_context & get_executor()
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)
static transaction_metadata_ptr create_no_recover_keys(packed_transaction_ptr trx, trx_type t)
#define FC_CAPTURE_AND_RETHROW(...)
#define edump(SEQ)
Definition logger.hpp:162
#define ilog(FORMAT,...)
Definition logger.hpp:118
#define elog(FORMAT,...)
Definition logger.hpp:130
void unpack(Stream &s, std::deque< T > &value)
Definition raw.hpp:540
std::future< transaction_metadata_ptr > recover_keys_future
std::shared_ptr< transaction_trace > transaction_trace_ptr
Definition trace.hpp:20
std::shared_ptr< const packed_transaction > packed_transaction_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 Block can not be found block_validate_exception
std::shared_ptr< signed_block > signed_block_ptr
Definition block.hpp:105
std::shared_ptr< transaction_metadata > transaction_metadata_ptr
transaction_trace_ptr push_scheduled_transaction(const transaction_id_type &trxid, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time=false)
void finalize_block()
start_block
void start_block(block_timestamp_type when, uint16_t confirm_block_count, const vector< digest_type > &new_protocol_feature_activations, controller::block_status s, const std::optional< block_id_type > &producer_block_id, const fc::time_point &deadline)
push_transaction
void commit_block(bool add_to_fork_db)
finalize_block
vector< transaction_metadata_ptr > abort_block()
push_block
transaction_trace_ptr push_transaction(const transaction_metadata_ptr &trx, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time, int64_t subjective_cpu_bill_us)
void report_block_header_diff(const block_header &b, const block_header &ab)
@ hard_fail
objectively failed and error handler objectively failed thus no state change
Definition block.hpp:16
Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_onerror()

transaction_trace_ptr sysio::chain::controller_impl::apply_onerror ( const generated_transaction & gtrx,
fc::time_point block_deadline,
fc::microseconds max_transaction_time,
fc::time_point start,
uint32_t & cpu_time_to_bill_us,
uint32_t billed_cpu_time_us,
bool explicit_billed_cpu_time = false,
bool enforce_whiteblacklist = true )
inline

Definition at line 1102 of file controller.cpp.

1111 {
1112 signed_transaction etrx;
1113 // Deliver onerror action containing the failed deferred transaction directly back to the sender.
1114 etrx.actions.emplace_back( vector<permission_level>{{gtrx.sender, config::active_name}},
1115 onerror( gtrx.sender_id, gtrx.packed_trx.data(), gtrx.packed_trx.size() ) );
1117 etrx.expiration = time_point_sec();
1118 etrx.ref_block_num = 0;
1119 etrx.ref_block_prefix = 0;
1120 } else {
1121 etrx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to nearest second to avoid appearing expired
1122 etrx.set_reference_block( self.head_block_id() );
1123 }
1124
1125 if (auto dm_logger = get_deep_mind_logger()) {
1126 dm_logger->on_onerror(etrx);
1127 }
1128
1129 transaction_checktime_timer trx_timer(timer);
1130 const packed_transaction trx( std::move( etrx ) );
1131 transaction_context trx_context( self, trx, std::move(trx_timer), start );
1132
1133 trx_context.block_deadline = block_deadline;
1134 trx_context.max_transaction_time_subjective = max_transaction_time;
1135 trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
1136 trx_context.billed_cpu_time_us = billed_cpu_time_us;
1137 trx_context.enforce_whiteblacklist = enforce_whiteblacklist;
1138 transaction_trace_ptr trace = trx_context.trace;
1139
1140 auto handle_exception = [&](const auto& e)
1141 {
1142 cpu_time_to_bill_us = trx_context.update_billed_cpu_time( fc::time_point::now() );
1143 trace->error_code = controller::convert_exception_to_error_code( e );
1144 trace->except = e;
1145 trace->except_ptr = std::current_exception();
1146 };
1147
1148 try {
1149 trx_context.init_for_implicit_trx();
1150 trx_context.published = gtrx.published;
1151 trx_context.execute_action( trx_context.schedule_action( trx.get_transaction().actions.back(), gtrx.sender, false, 0, 0 ), 0 );
1152 trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
1153
1154 auto restore = make_block_restore_point();
1155 trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::soft_fail,
1156 trx_context.billed_cpu_time_us, trace->net_usage );
1157 fc::move_append( std::get<building_block>(pending->_block_stage)._action_receipt_digests,
1158 std::move(trx_context.executed_action_receipt_digests) );
1159
1160 trx_context.squash();
1161 restore.cancel();
1162 return trace;
1163 } catch( const disallowed_transaction_extensions_bad_block_exception& ) {
1164 throw;
1165 } catch( const protocol_feature_bad_block_exception& ) {
1166 throw;
1167 } catch ( const std::bad_alloc& ) {
1168 throw;
1169 } catch ( const boost::interprocess::bad_alloc& ) {
1170 throw;
1171 } catch( const fc::exception& e ) {
1172 handle_exception(e);
1173 } catch ( const std::exception& e ) {
1175 handle_exception(wrapper);
1176 }
1177 return trace;
1178 }
static std_exception_wrapper from_current_exception(const std::exception &e)
static time_point now()
Definition time.cpp:14
block_id_type head_block_id() const
bool is_builtin_activated(builtin_protocol_feature_t f) const
time_point pending_block_time() const
static std::optional< uint64_t > convert_exception_to_error_code(const fc::exception &e)
void move_append(Container &dest, Container &&src)
Definition utility.hpp:151
deep_mind_handler * get_deep_mind_logger() const
fc::scoped_exit< std::function< void()> > make_block_restore_point()
const transaction_receipt & push_receipt(const T &trx, transaction_receipt_header::status_enum status, uint64_t cpu_usage_us, uint64_t net_usage)
push_scheduled_transaction
@ soft_fail
objectively failed (not executed), error handler executed
Definition block.hpp:15
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_integrity_hash()

sha256 sysio::chain::controller_impl::calculate_integrity_hash ( )
inline

Definition at line 978 of file controller.cpp.

978 {
979 sha256::encoder enc;
980 auto hash_writer = std::make_shared<integrity_hash_snapshot_writer>(enc);
981 add_to_snapshot(hash_writer);
982 hash_writer->finalize();
983
984 return enc.result();
985 }
void add_to_snapshot(const snapshot_writer_ptr &snapshot)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_trx_merkle()

static checksum256_type sysio::chain::controller_impl::calculate_trx_merkle ( const vector< transaction_receipt > & trxs)
inlinestatic

Definition at line 2325 of file controller.cpp.

2325 {
2326 vector<digest_type> trx_digests;
2327 trx_digests.reserve( trxs.size() );
2328 for( const auto& a : trxs )
2329 trx_digests.emplace_back( a.digest() );
2330
2331 return merkle( move(trx_digests) );
2332 }
digest_type merkle(vector< digest_type > ids)
Definition merkle.cpp:35
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_action_list()

void sysio::chain::controller_impl::check_action_list ( account_name code,
action_name action ) const
inline

Definition at line 2506 of file controller.cpp.

2506 {
2507 if( conf.action_blacklist.size() > 0 ) {
2508 SYS_ASSERT( conf.action_blacklist.find( std::make_pair(code, action) ) == conf.action_blacklist.end(),
2509 action_blacklist_exception,
2510 "action '${code}::${action}' is on the action blacklist",
2511 ("code", code)("action", action)
2512 );
2513 }
2514 }
flat_set< pair< account_name, action_name > > action_blacklist

◆ check_actor_list()

void sysio::chain::controller_impl::check_actor_list ( const flat_set< account_name > & actors) const
inline

Definition at line 2407 of file controller.cpp.

2407 {
2408 if( actors.size() == 0 ) return;
2409
2410 if( conf.actor_whitelist.size() > 0 ) {
2411 // throw if actors is not a subset of whitelist
2412 const auto& whitelist = conf.actor_whitelist;
2413 bool is_subset = true;
2414
2415 // quick extents check, then brute force the check actors
2416 if (*actors.cbegin() >= *whitelist.cbegin() && *actors.crbegin() <= *whitelist.crbegin() ) {
2417 auto lower_bound = whitelist.cbegin();
2418 for (const auto& actor: actors) {
2419 lower_bound = std::lower_bound(lower_bound, whitelist.cend(), actor);
2420
2421 // if the actor is not found, this is not a subset
2422 if (lower_bound == whitelist.cend() || *lower_bound != actor ) {
2423 is_subset = false;
2424 break;
2425 }
2426
2427 // if the actor was found, we are guaranteed that other actors are either not present in the whitelist
2428 // or will be present in the range defined as [next actor,end)
2429 lower_bound = std::next(lower_bound);
2430 }
2431 } else {
2432 is_subset = false;
2433 }
2434
2435 // helper lambda to lazily calculate the actors for error messaging
2436 static auto generate_missing_actors = [](const flat_set<account_name>& actors, const flat_set<account_name>& whitelist) -> vector<account_name> {
2437 vector<account_name> excluded;
2438 excluded.reserve( actors.size() );
2439 set_difference( actors.begin(), actors.end(),
2440 whitelist.begin(), whitelist.end(),
2441 std::back_inserter(excluded) );
2442 return excluded;
2443 };
2444
2445 SYS_ASSERT( is_subset, actor_whitelist_exception,
2446 "authorizing actor(s) in transaction are not on the actor whitelist: ${actors}",
2447 ("actors", generate_missing_actors(actors, whitelist))
2448 );
2449 } else if( conf.actor_blacklist.size() > 0 ) {
2450 // throw if actors intersects blacklist
2451 const auto& blacklist = conf.actor_blacklist;
2452 bool intersects = false;
2453
2454 // quick extents check then brute force check actors
2455 if( *actors.cbegin() <= *blacklist.crbegin() && *actors.crbegin() >= *blacklist.cbegin() ) {
2456 auto lower_bound = blacklist.cbegin();
2457 for (const auto& actor: actors) {
2458 lower_bound = std::lower_bound(lower_bound, blacklist.cend(), actor);
2459
2460 // if the lower bound in the blacklist is at the end, all other actors are guaranteed to
2461 // not exist in the blacklist
2462 if (lower_bound == blacklist.cend()) {
2463 break;
2464 }
2465
2466 // if the lower bound of an actor IS the actor, then we have an intersection
2467 if (*lower_bound == actor) {
2468 intersects = true;
2469 break;
2470 }
2471 }
2472 }
2473
2474 // helper lambda to lazily calculate the actors for error messaging
2475 static auto generate_blacklisted_actors = [](const flat_set<account_name>& actors, const flat_set<account_name>& blacklist) -> vector<account_name> {
2476 vector<account_name> blacklisted;
2477 blacklisted.reserve( actors.size() );
2478 set_intersection( actors.begin(), actors.end(),
2479 blacklist.begin(), blacklist.end(),
2480 std::back_inserter(blacklisted)
2481 );
2482 return blacklisted;
2483 };
2484
2485 SYS_ASSERT( !intersects, actor_blacklist_exception,
2486 "authorizing actor(s) in transaction are on the actor blacklist: ${actors}",
2487 ("actors", generate_blacklisted_actors(actors, blacklist))
2488 );
2489 }
2490 }
const std::set< std::string > blacklist
flat_set< account_name > actor_blacklist
flat_set< account_name > actor_whitelist
Here is the caller graph for this function:

◆ check_contract_list()

void sysio::chain::controller_impl::check_contract_list ( account_name code) const
inline

Definition at line 2492 of file controller.cpp.

2492 {
2493 if( conf.contract_whitelist.size() > 0 ) {
2495 contract_whitelist_exception,
2496 "account '${code}' is not on the contract whitelist", ("code", code)
2497 );
2498 } else if( conf.contract_blacklist.size() > 0 ) {
2500 contract_blacklist_exception,
2501 "account '${code}' is on the contract blacklist", ("code", code)
2502 );
2503 }
2504 }
flat_set< account_name > contract_whitelist
flat_set< account_name > contract_blacklist

◆ check_key_list()

void sysio::chain::controller_impl::check_key_list ( const public_key_type & key) const
inline

Definition at line 2516 of file controller.cpp.

2516 {
2517 if( conf.key_blacklist.size() > 0 ) {
2518 SYS_ASSERT( conf.key_blacklist.find( key ) == conf.key_blacklist.end(),
2519 key_blacklist_exception,
2520 "public key '${key}' is on the key blacklist",
2521 ("key", key)
2522 );
2523 }
2524 }
flat_set< public_key_type > key_blacklist

◆ check_protocol_features()

void sysio::chain::controller_impl::check_protocol_features ( block_timestamp_type timestamp,
const flat_set< digest_type > & currently_activated_protocol_features,
const vector< digest_type > & new_protocol_features )
inline

This method is called from other threads. The controller_impl should outlive those threads. However, to avoid race conditions, it means that the behavior of this function should not change after controller_impl construction.

This should not be an issue since the purpose of this function is to ensure all of the protocol features in the supplied vector are recognized by the software, and the set of recognized protocol features is determined at startup and cannot be changed without a restart.

Definition at line 1875 of file controller.cpp.

1878 {
1879 const auto& pfs = protocol_features.get_protocol_feature_set();
1880
1881 for( auto itr = new_protocol_features.begin(); itr != new_protocol_features.end(); ++itr ) {
1882 const auto& f = *itr;
1883
1884 auto status = pfs.is_recognized( f, timestamp );
1885 switch( status ) {
1887 SYS_THROW( protocol_feature_exception,
1888 "protocol feature with digest '${digest}' is unrecognized", ("digest", f) );
1889 break;
1891 SYS_THROW( protocol_feature_exception,
1892 "protocol feature with digest '${digest}' is disabled", ("digest", f) );
1893 break;
1895 SYS_THROW( protocol_feature_exception,
1896 "${timestamp} is too early for the earliest allowed activation time of the protocol feature with digest '${digest}'", ("digest", f)("timestamp", timestamp) );
1897 break;
1899 break;
1900 default:
1901 SYS_THROW( protocol_feature_exception, "unexpected recognized_t status" );
1902 break;
1903 }
1904
1905 SYS_ASSERT( currently_activated_protocol_features.find( f ) == currently_activated_protocol_features.end(),
1906 protocol_feature_exception,
1907 "protocol feature with digest '${digest}' has already been activated",
1908 ("digest", f)
1909 );
1910
1911 auto dependency_checker = [&currently_activated_protocol_features, &new_protocol_features, &itr]
1912 ( const digest_type& f ) -> bool
1913 {
1914 if( currently_activated_protocol_features.find( f ) != currently_activated_protocol_features.end() )
1915 return true;
1916
1917 return (std::find( new_protocol_features.begin(), itr, f ) != itr);
1918 };
1919
1920 SYS_ASSERT( pfs.validate_dependencies( f, dependency_checker ), protocol_feature_exception,
1921 "not all dependencies of protocol feature with digest '${digest}' have been activated",
1922 ("digest", f)
1923 );
1924 }
1925 }
#define SYS_THROW(exc_type, FORMAT,...)
const protocol_feature_set & get_protocol_feature_set() const
checksum_type digest_type
Definition types.hpp:237
Here is the call graph for this function:

◆ clear_all_undo()

void sysio::chain::controller_impl::clear_all_undo ( )
inline

Definition at line 737 of file controller.cpp.

737 {
738 // Rewind the database to the last irreversible block
739 db.undo_all();
740 /*
741 FC_ASSERT(db.revision() == self.head_block_num(),
742 "Chainbase revision does not match head block num",
743 ("rev", db.revision())("head_block", self.head_block_num()));
744 */
745 }
Here is the call graph for this function:

◆ clear_expired_input_transactions()

void sysio::chain::controller_impl::clear_expired_input_transactions ( const fc::time_point & deadline)
inline

Definition at line 2379 of file controller.cpp.

2379 {
2380 //Look for expired transactions in the deduplication list, and remove them.
2381 auto& transaction_idx = db.get_mutable_index<transaction_multi_index>();
2382 const auto& dedupe_index = transaction_idx.indices().get<by_expiration>();
2384 const auto total = dedupe_index.size();
2385 uint32_t num_removed = 0;
2386 while( (!dedupe_index.empty()) && ( now > fc::time_point(dedupe_index.begin()->expiration) ) ) {
2387 transaction_idx.remove(*dedupe_index.begin());
2388 ++num_removed;
2389 if( deadline <= fc::time_point::now() ) {
2390 break;
2391 }
2392 }
2393 dlog("removed ${n} expired transactions of the ${t} input dedup list, pending block time ${pt}",
2394 ("n", num_removed)("t", total)("pt", now));
2395 }
generic_index< MultiIndexType > & get_mutable_index()
time_point head_block_time() const
#define dlog(FORMAT,...)
Definition logger.hpp:101
chainbase::shared_multi_index_container< transaction_object, indexed_by< ordered_unique< tag< by_id >, BOOST_MULTI_INDEX_MEMBER(transaction_object, transaction_object::id_type, id)>, ordered_unique< tag< by_trx_id >, BOOST_MULTI_INDEX_MEMBER(transaction_object, transaction_id_type, trx_id)>, ordered_unique< tag< by_expiration >, composite_key< transaction_object, BOOST_MULTI_INDEX_MEMBER(transaction_object, time_point_sec, expiration), > > > > transaction_multi_index
unsigned int uint32_t
Definition stdint.h:126
Here is the call graph for this function:
Here is the caller graph for this function:

◆ commit_block()

void sysio::chain::controller_impl::commit_block ( bool add_to_fork_db)
inline
Postcondition
regardless of the success of commit block there is no active pending block

Definition at line 1827 of file controller.cpp.

1827 {
1828 auto reset_pending_on_exit = fc::make_scoped_exit([this]{
1829 pending.reset();
1830 });
1831
1832 try {
1833 SYS_ASSERT( std::holds_alternative<completed_block>(pending->_block_stage), block_validate_exception,
1834 "cannot call commit_block until pending block is completed" );
1835
1836 auto bsp = std::get<completed_block>(pending->_block_stage)._block_state;
1837
1838 if( add_to_fork_db ) {
1839 fork_db.add( bsp );
1840 fork_db.mark_valid( bsp );
1842 head = fork_db.head();
1843 SYS_ASSERT( bsp == head, fork_database_exception, "committed block did not become the new head in fork database");
1844 }
1845
1846 if (auto dm_logger = get_deep_mind_logger()) {
1847 dm_logger->on_accepted_block(bsp);
1848 }
1849
1850 emit( self.accepted_block, bsp );
1851
1852 if( add_to_fork_db ) {
1854 }
1855 } catch (...) {
1856 // dont bother resetting pending, instead abort the block
1857 reset_pending_on_exit.cancel();
1858 abort_block();
1859 throw;
1860 }
1861
1862 // push the state for pending.
1863 pending->push();
1864 }
signal< void(const block_state_ptr &)> accepted_block_header
signal< void(const block_state_ptr &)> accepted_block
block_state_ptr head() const
void mark_valid(const block_state_ptr &h)
void add(const block_state_ptr &next_block, bool ignore_duplicate=false)
scoped_exit< Callback > make_scoped_exit(Callback &&c)
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
void emit(const Signal &s, Arg &&a)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_block_state()

block_state_ptr sysio::chain::controller_impl::create_block_state ( const block_id_type & id,
const signed_block_ptr & b )
inline

Definition at line 2119 of file controller.cpp.

2119 {
2120 SYS_ASSERT( b, block_validate_exception, "null block" );
2121
2122 // no reason for a block_state if fork_db already knows about block
2123 auto existing = fork_db.get_block( id );
2124 SYS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
2125
2126 // previous not found could mean that previous block not applied yet
2127 auto prev = fork_db.get_block_header( b->previous );
2128 if( !prev ) return {};
2129
2130 return create_block_state_i( id, b, *prev );
2131 }
block_header_state_ptr get_block_header(const block_id_type &id) const
block_state_ptr get_block(const block_id_type &id) const
block_state_ptr create_block_state_i(const block_id_type &id, const signed_block_ptr &b, const block_header_state &prev)
apply_block
Here is the call graph for this function:

◆ create_block_state_future()

std::future< block_state_ptr > sysio::chain::controller_impl::create_block_state_future ( const block_id_type & id,
const signed_block_ptr & b )
inline

Definition at line 2102 of file controller.cpp.

2102 {
2103 SYS_ASSERT( b, block_validate_exception, "null block" );
2104
2105 return async_thread_pool( thread_pool.get_executor(), [b, id, control=this]() {
2106 // no reason for a block_state if fork_db already knows about block
2107 auto existing = control->fork_db.get_block( id );
2108 SYS_ASSERT( !existing, fork_database_exception, "we already know about this block: ${id}", ("id", id) );
2109
2110 auto prev = control->fork_db.get_block_header( b->previous );
2111 SYS_ASSERT( prev, unlinkable_block_exception,
2112 "unlinkable block ${id}", ("id", id)("previous", b->previous) );
2113
2114 return control->create_block_state_i( id, b, *prev );
2115 } );
2116 }
auto async_thread_pool(boost::asio::io_context &thread_pool, F &&f)
Here is the call graph for this function:

◆ create_block_state_i()

block_state_ptr sysio::chain::controller_impl::create_block_state_i ( const block_id_type & id,
const signed_block_ptr & b,
const block_header_state & prev )
inline

Definition at line 2080 of file controller.cpp.

2080 {
2081 auto trx_mroot = calculate_trx_merkle( b->transactions );
2082 SYS_ASSERT( b->transaction_mroot == trx_mroot, block_validate_exception,
2083 "invalid block transaction merkle root ${b} != ${c}", ("b", b->transaction_mroot)("c", trx_mroot) );
2084
2085 const bool skip_validate_signee = false;
2086 auto bsp = std::make_shared<block_state>(
2087 prev,
2088 b,
2090 [this]( block_timestamp_type timestamp,
2091 const flat_set<digest_type>& cur_features,
2092 const vector<digest_type>& new_features )
2093 { check_protocol_features( timestamp, cur_features, new_features ); },
2094 skip_validate_signee
2095 );
2096
2097 SYS_ASSERT( id == bsp->id, block_validate_exception,
2098 "provided id ${id} does not match block id ${bid}", ("id", id)("bid", bsp->id) );
2099 return bsp;
2100 }
static checksum256_type calculate_trx_merkle(const vector< transaction_receipt > &trxs)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_block_summary()

void sysio::chain::controller_impl::create_block_summary ( const block_id_type & id)
inline

Definition at line 2370 of file controller.cpp.

2370 {
2371 auto block_num = block_header::num_from_id(id);
2372 auto sid = block_num & 0xffff;
2373 db.modify( db.get<block_summary_object,by_id>(sid), [&](block_summary_object& bso ) {
2374 bso.block_id = id;
2375 });
2376 }
void modify(const ObjectType &obj, Modifier &&m)
const ObjectType & get(CompatibleKey &&key) const
static uint32_t num_from_id(const block_id_type &id)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_native_account()

void sysio::chain::controller_impl::create_native_account ( const fc::time_point & initial_timestamp,
account_name name,
const authority & owner,
const authority & active,
bool is_privileged = false )
inline

Definition at line 987 of file controller.cpp.

987 {
988 db.create<account_object>([&](auto& a) {
989 a.name = name;
990 a.creation_date = initial_timestamp;
991
992 if( name == config::system_account_name ) {
993 // The initial sysio ABI value affects consensus; see https://github.com/SYSIO/eos/issues/7794
994 // TODO: This doesn't charge RAM; a fix requires a consensus upgrade.
995 a.abi.assign(sysio_abi_bin, sizeof(sysio_abi_bin));
996 }
997 });
998 db.create<account_metadata_object>([&](auto & a) {
999 a.name = name;
1000 a.set_privileged( is_privileged );
1001 });
1002
1003 const auto& owner_permission = authorization.create_permission(name, config::owner_name, 0,
1004 owner, initial_timestamp );
1005 const auto& active_permission = authorization.create_permission(name, config::active_name, owner_permission.id,
1006 active, initial_timestamp );
1007
1009
1010 int64_t ram_delta = config::overhead_per_account_ram_bytes;
1012 ram_delta += owner_permission.auth.get_billable_size();
1013 ram_delta += active_permission.auth.get_billable_size();
1014
1015 if (auto dm_logger = get_deep_mind_logger()) {
1016 dm_logger->on_ram_trace(RAM_EVENT_ID("${name}", ("name", name)), "account", "add", "newaccount");
1017 }
1018
1021 }
std::string name
const ObjectType & create(Constructor &&con)
const permission_object & create_permission(account_name account, permission_name name, permission_id_type parent, const authority &auth, time_point initial_creation_time=time_point())
void add_pending_ram_usage(const account_name account, int64_t ram_delta)
void verify_account_ram_usage(const account_name accunt) const
#define RAM_EVENT_ID(FORMAT,...)
Definition deep_mind.hpp:27
constexpr uint64_t billable_size_v
Definition config.hpp:147
unsigned char sysio_abi_bin[2132]
signed __int64 int64_t
Definition stdint.h:135
Here is the call graph for this function:
Here is the caller graph for this function:

◆ dmlog_applied_transaction()

void sysio::chain::controller_impl::dmlog_applied_transaction ( const transaction_trace_ptr & t)
inline

Definition at line 389 of file controller.cpp.

389 {
390 if (auto dm_logger = get_deep_mind_logger()) {
391 dm_logger->on_applied_transaction(self.head_block_num() + 1, t);
392 }
393 }
uint32_t head_block_num() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ earliest_available_block_num()

uint32_t sysio::chain::controller_impl::earliest_available_block_num ( ) const
inline

Definition at line 2576 of file controller.cpp.

2576 {
2577 return (blog.first_block_num() != 0) ? blog.first_block_num() : fork_db.root()->block_num;
2578 }
uint32_t first_block_num() const
block_state_ptr root() const
Here is the call graph for this function:

◆ emit()

template<typename Signal , typename Arg >
void sysio::chain::controller_impl::emit ( const Signal & s,
Arg && a )
inline

Plugins / observers listening to signals emited (such as accepted_transaction) might trigger errors and throw exceptions. Unless those exceptions are caught it could impact consensus and/or cause a node to fork.

If it is ever desirable to let a signal handler bubble an exception out of this method a full audit of its uses needs to be undertaken.

Definition at line 368 of file controller.cpp.

368 {
369 try {
370 s( std::forward<Arg>( a ));
371 } catch (std::bad_alloc& e) {
372 wlog( "std::bad_alloc: ${w}", ("w", e.what()) );
373 throw e;
374 } catch (boost::interprocess::bad_alloc& e) {
375 wlog( "boost::interprocess::bad alloc: ${w}", ("w", e.what()) );
376 throw e;
377 } catch ( controller_emit_signal_exception& e ) {
378 wlog( "controller_emit_signal_exception: ${details}", ("details", e.to_detail_string()) );
379 throw e;
380 } catch ( fc::exception& e ) {
381 wlog( "fc::exception: ${details}", ("details", e.to_detail_string()) );
382 } catch ( std::exception& e ) {
383 wlog( "std::exception: ${details}", ("details", e.what()) );
384 } catch ( ... ) {
385 wlog( "signal handler threw exception" );
386 }
387 }
#define wlog(FORMAT,...)
Definition logger.hpp:124
Here is the caller graph for this function:

◆ extract_legacy_genesis_state()

static std::optional< genesis_state > sysio::chain::controller_impl::extract_legacy_genesis_state ( snapshot_reader & snapshot,
uint32_t version )
inlinestatic

Definition at line 840 of file controller.cpp.

840 {
841 std::optional<genesis_state> genesis;
842 using v2 = legacy::snapshot_global_property_object_v2;
843
844 if (std::clamp(version, v2::minimum_version, v2::maximum_version) == version ) {
845 genesis.emplace();
846 snapshot.read_section<genesis_state>([&genesis=*genesis]( auto &section ){
847 section.read_row(genesis);
848 });
849 }
850 return genesis;
851 }
Here is the caller graph for this function:

◆ failure_is_subjective()

bool sysio::chain::controller_impl::failure_is_subjective ( const fc::exception & e) const
inline

Definition at line 1193 of file controller.cpp.

1193 {
1194 auto code = e.code();
1195 return (code == subjective_block_production_exception::code_value)
1196 || (code == block_net_usage_exceeded::code_value)
1197 || (code == greylist_net_usage_exceeded::code_value)
1198 || (code == block_cpu_usage_exceeded::code_value)
1199 || (code == greylist_cpu_usage_exceeded::code_value)
1200 || (code == deadline_exception::code_value)
1201 || (code == leeway_deadline_exception::code_value)
1202 || (code == actor_whitelist_exception::code_value)
1203 || (code == actor_blacklist_exception::code_value)
1204 || (code == contract_whitelist_exception::code_value)
1205 || (code == contract_blacklist_exception::code_value)
1206 || (code == action_blacklist_exception::code_value)
1207 || (code == key_blacklist_exception::code_value)
1208 || (code == sig_variable_size_limit_exception::code_value)
1209 || (code == inline_action_too_big_nonprivileged::code_value);
1210 }
int64_t code() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ finalize_block()

void sysio::chain::controller_impl::finalize_block ( )
inline

Definition at line 1759 of file controller.cpp.

1760 {
1761 SYS_ASSERT( pending, block_validate_exception, "it is not valid to finalize when there is no pending block");
1762 SYS_ASSERT( std::holds_alternative<building_block>(pending->_block_stage), block_validate_exception, "already called finalize_block");
1763
1764 try {
1765
1766 auto& pbhs = pending->get_pending_block_header_state();
1767
1768 // Update resource limits:
1773 { CPU_TARGET, chain_config.max_block_cpu_usage, config::block_cpu_usage_average_window_ms / config::block_interval_ms, config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}},
1774 {SYS_PERCENT(chain_config.max_block_net_usage, chain_config.target_block_net_usage_pct), chain_config.max_block_net_usage, config::block_size_average_window_ms / config::block_interval_ms, config::maximum_elastic_resource_multiplier, {99, 100}, {1000, 999}}
1775 );
1776 resource_limits.process_block_usage(pbhs.block_num);
1777
1778 auto& bb = std::get<building_block>(pending->_block_stage);
1779
1780 if (bb._s_header){
1781 ilog("s_header present in finalize block, adding to block header: ${s}", ("s", bb._s_header->to_string()));
1782 }
1783
1784 // Create (unsigned) block:
1785 auto block_ptr = std::make_shared<signed_block>( pbhs.make_block_header(
1786 bb._transaction_mroot ? *bb._transaction_mroot : calculate_trx_merkle( bb._pending_trx_receipts ),
1787 merkle( std::move( std::get<building_block>(pending->_block_stage)._action_receipt_digests ) ),
1788 bb._new_pending_producer_schedule,
1789 std::move( bb._new_protocol_feature_activations ),
1791 bb._s_header // Include optional s_header in block header
1792 ) );
1793
1794 block_ptr->transactions = std::move( bb._pending_trx_receipts );
1795
1796 auto id = block_ptr->calculate_id();
1797
1798 // Update TaPoS table:
1800
1801 /*
1802 ilog( "finalized block ${n} (${id}) at ${t} by ${p} (${signing_key}); schedule_version: ${v} lib: ${lib} #dtrxs: ${ndtrxs} ${np}",
1803 ("n",pbhs.block_num)
1804 ("id",id)
1805 ("t",pbhs.timestamp)
1806 ("p",pbhs.producer)
1807 ("signing_key", pbhs.block_signing_key)
1808 ("v",pbhs.active_schedule_version)
1809 ("lib",pbhs.dpos_irreversible_blocknum)
1810 ("ndtrxs",db.get_index<generated_transaction_multi_index,by_trx_id>().size())
1811 ("np",block_ptr->new_producers)
1812 );
1813 */
1814
1815 pending->_block_stage = assembled_block{
1816 id,
1817 std::move( bb._pending_block_header_state ),
1818 std::move( bb._pending_trx_metas ),
1819 std::move( block_ptr ),
1820 std::move( bb._new_pending_producer_schedule )
1821 };
constexpr uint64_t SYS_PERCENT(uint64_t value, uint32_t percentage)
Definition config.hpp:152
const global_property_object & get_global_properties() const
void set_block_parameters(const elastic_limit_parameters &cpu_limit_parameters, const elastic_limit_parameters &net_limit_parameters)
uint64_t id
Definition code_cache.cpp:0
chain_config_v1 chain_config
unsigned __int64 uint64_t
Definition stdint.h:136
uint32_t target_block_net_usage_pct
the target percent (1% == 100, 100%= 10,000) of maximum net usage; exceeding this triggers congestion...
uint32_t max_block_cpu_usage
the maxiumum billable cpu usage (in microseconds) for a block
uint64_t max_block_net_usage
the maxiumum net usage in instructions for a block
uint32_t target_block_cpu_usage_pct
the target percent (1% == 100, 100%= 10,000) of maximum cpu usage; exceeding this triggers congestion...
void create_block_summary(const block_id_type &id)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_deep_mind_logger()

deep_mind_handler * sysio::chain::controller_impl::get_deep_mind_logger ( ) const
inline

Definition at line 2572 of file controller.cpp.

2572 {
2573 return deep_mind_logger;
2574 }
deep_mind_handler * deep_mind_logger
Here is the caller graph for this function:

◆ get_on_block_transaction()

signed_transaction sysio::chain::controller_impl::get_on_block_transaction ( )
inline

At the start of each block we notify the system contract with a transaction that passes in the block header of the prior block (which is currently our head block)

Definition at line 2546 of file controller.cpp.

2547 {
2548 action on_block_act;
2549 on_block_act.account = config::system_account_name;
2550 on_block_act.name = "onblock"_n;
2551 on_block_act.authorization = vector<permission_level>{{config::system_account_name, config::active_name}};
2552 on_block_act.data = fc::raw::pack(self.head_block_header());
2553
2554 signed_transaction trx;
2555 trx.actions.emplace_back(std::move(on_block_act));
2557 trx.expiration = time_point_sec();
2558 trx.ref_block_num = 0;
2559 trx.ref_block_prefix = 0;
2560 } else {
2561 trx.expiration = self.pending_block_time() + fc::microseconds(999'999); // Round up to nearest second to avoid appearing expired
2562 trx.set_reference_block( self.head_block_id() );
2563 }
2564
2565 if (auto dm_logger = get_deep_mind_logger()) {
2566 dm_logger->on_onblock(trx);
2567 }
2568
2569 return trx;
2570 }
const block_header & head_block_header() const
void pack(Stream &s, const std::deque< T > &value)
Definition raw.hpp:531
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init()

void sysio::chain::controller_impl::init ( std::function< bool()> check_shutdown)
inline

Definition at line 662 of file controller.cpp.

662 {
663 auto header_itr = validate_db_version( db );
664
665 {
666 const auto& state_chain_id = db.get<global_property_object>().chain_id;
667 SYS_ASSERT( state_chain_id == chain_id, chain_id_type_exception,
668 "chain ID in state (${state_chain_id}) does not match the chain ID that controller was constructed with (${controller_chain_id})",
669 ("state_chain_id", state_chain_id)("controller_chain_id", chain_id)
670 );
671 }
672
673 // upgrade to the latest compatible version
674 if (header_itr->version != database_header_object::current_version) {
675 db.modify(*header_itr, [](auto& header) {
676 header.version = database_header_object::current_version;
677 });
678 }
679
680 // At this point head != nullptr
682 "fork database head (${head}) is inconsistent with state (${db})",
683 ("db",db.revision())("head",head->block_num) );
684
685 if( db.revision() > head->block_num ) {
686 wlog( "database revision (${db}) is greater than head block number (${head}), "
687 "attempting to undo pending changes",
688 ("db",db.revision())("head",head->block_num) );
689 }
690 while( db.revision() > head->block_num ) {
691 db.undo();
692 }
693
695
696 if (auto dm_logger = get_deep_mind_logger()) {
697 dm_logger->on_startup(db, head->block_num);
698 }
699
700 replay( check_shutdown ); // replay any irreversible and reversible blocks ahead of current head
701
702 if( check_shutdown() ) return;
703
704 // At this point head != nullptr && fork_db.head() != nullptr && fork_db.root() != nullptr.
705 // Furthermore, fork_db.root()->block_num <= lib_num.
706 // Also, even though blog.head() may still be nullptr, blog.first_block_num() is guaranteed to be lib_num + 1.
707
709 && fork_db.pending_head()->id != fork_db.head()->id
710 && fork_db.head()->id == fork_db.root()->id
711 ) {
712 wlog( "read_mode has changed from irreversible: applying best branch from fork database" );
713
714 for( auto pending_head = fork_db.pending_head();
715 pending_head->id != fork_db.head()->id;
716 pending_head = fork_db.pending_head()
717 ) {
718 wlog( "applying branch from fork database ending with block: ${id}", ("id", pending_head->id) );
720 }
721 }
722 }
int64_t revision() const
@ complete
this is a complete block signed by a valid producer but is not yet irreversible nor has it yet been a...
block_state_ptr pending_head() const
std::function< transaction_metadata_ptr(const transaction_id_type &)> trx_meta_cache_lookup
std::function< void(const branch_type &)> forked_branch_callback
void replay(std::function< bool()> check_shutdown)
static auto validate_db_version(const chainbase::database &db)
void maybe_switch_forks(const block_state_ptr &new_head, controller::block_status s, const forked_branch_callback &forked_branch_cb, const trx_meta_cache_lookup &trx_lookup)
Here is the call graph for this function:

◆ initialize_blockchain_state()

void sysio::chain::controller_impl::initialize_blockchain_state ( const genesis_state & genesis)
inline

Sets fork database head to the genesis state.

Definition at line 452 of file controller.cpp.

452 {
453 wlog( "Initializing new blockchain with genesis state" );
454 producer_authority_schedule initial_schedule = { 0, { producer_authority{config::system_account_name, block_signing_authority_v0{ 1, {{genesis.initial_key, 1}} } } } };
455 legacy::producer_schedule_type initial_legacy_schedule{ 0, {{config::system_account_name, genesis.initial_key}} };
456
457 block_header_state genheader;
458 genheader.active_schedule = initial_schedule;
459 genheader.pending_schedule.schedule = initial_schedule;
460 // NOTE: if wtmsig block signatures are enabled at genesis time this should be the hash of a producer authority schedule
461 genheader.pending_schedule.schedule_hash = fc::sha256::hash(initial_legacy_schedule);
462 genheader.header.timestamp = genesis.initial_timestamp;
463 genheader.header.action_mroot = genesis.compute_chain_id();
464 genheader.id = genheader.header.calculate_id();
465 genheader.block_num = genheader.header.block_num();
466
467 head = std::make_shared<block_state>();
468 static_cast<block_header_state&>(*head) = genheader;
469 head->activated_protocol_features = std::make_shared<protocol_feature_activation_set>();
470 head->block = std::make_shared<signed_block>(genheader.header);
471 db.set_revision( head->block_num );
472 initialize_database(genesis);
473 }
void set_revision(uint64_t revision)
static sha256 hash(const char *d, uint32_t dlen)
Definition sha256.cpp:44
void initialize_database(const genesis_state &genesis)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ initialize_database()

void sysio::chain::controller_impl::initialize_database ( const genesis_state & genesis)
inline

Definition at line 1023 of file controller.cpp.

1023 {
1024 // create the database header sigil
1025 db.create<database_header_object>([&]( auto& header ){
1026 // nothing to do for now
1027 });
1028
1029 // Initialize block summary index
1030 for (int i = 0; i < 0x10000; i++)
1031 db.create<block_summary_object>([&](block_summary_object&) {});
1032
1033 const auto& tapos_block_summary = db.get<block_summary_object>(1);
1034 db.modify( tapos_block_summary, [&]( auto& bs ) {
1035 bs.block_id = head->id;
1036 });
1037
1038 genesis.initial_configuration.validate();
1039 db.create<global_property_object>([&genesis,&chain_id=this->chain_id](auto& gpo ){
1040 gpo.configuration = genesis.initial_configuration;
1041 // TODO: Update this when genesis protocol features are enabled.
1043 gpo.chain_id = chain_id;
1044 });
1045
1046 db.create<protocol_state_object>([&](auto& pso ){
1047 pso.num_supported_key_types = config::genesis_num_supported_key_types;
1048 for( const auto& i : genesis_intrinsics ) {
1049 add_intrinsic_to_whitelist( pso.whitelisted_intrinsics, i );
1050 }
1051 });
1052
1053 db.create<dynamic_global_property_object>([](auto&){});
1054
1057
1058 authority system_auth(genesis.initial_key);
1059 create_native_account( genesis.initial_timestamp, config::system_account_name, system_auth, system_auth, true );
1060
1061 auto empty_authority = authority(1, {}, {});
1062 auto active_producers_authority = authority(1, {}, {});
1063 active_producers_authority.accounts.push_back({{config::system_account_name, config::active_name}, 1});
1064
1065 create_native_account( genesis.initial_timestamp, config::null_account_name, empty_authority, empty_authority );
1066 create_native_account( genesis.initial_timestamp, config::producers_account_name, empty_authority, active_producers_authority );
1067 const auto& active_permission = authorization.get_permission({config::producers_account_name, config::active_name});
1068 const auto& majority_permission = authorization.create_permission( config::producers_account_name,
1069 config::majority_producers_permission_name,
1070 active_permission.id,
1071 active_producers_authority,
1072 genesis.initial_timestamp );
1073 authorization.create_permission( config::producers_account_name,
1074 config::minority_producers_permission_name,
1075 majority_permission.id,
1076 active_producers_authority,
1077 genesis.initial_timestamp );
1078
1079 }
const permission_object & get_permission(const permission_level &level) const
const std::vector< const char * > genesis_intrinsics
void add_intrinsic_to_whitelist(whitelisted_intrinsics_type &whitelisted_intrinsics, std::string_view name)
void create_native_account(const fc::time_point &initial_timestamp, account_name name, const authority &owner, const authority &active, bool is_privileged=false)
static constexpr wasm_config default_initial_wasm_configuration
Here is the call graph for this function:
Here is the caller graph for this function:

◆ log_irreversible()

void sysio::chain::controller_impl::log_irreversible ( )
inline

Definition at line 395 of file controller.cpp.

395 {
396 SYS_ASSERT( fork_db.root(), fork_database_exception, "fork database not properly initialized" );
397
398 const auto& log_head = blog.head();
399
400 auto lib_num = log_head ? log_head->block_num() : (blog.first_block_num() - 1);
401
402 auto root_id = fork_db.root()->id;
403
404 if( log_head ) {
405 SYS_ASSERT( root_id == blog.head_id(), fork_database_exception, "fork database root does not match block log head" );
406 } else {
407 SYS_ASSERT( fork_db.root()->block_num == lib_num, fork_database_exception,
408 "empty block log expects the first appended block to build off a block that is not the fork database root. root block number: ${block_num}, lib: ${lib_num}", ("block_num", fork_db.root()->block_num) ("lib_num", lib_num) );
409 }
410
412
413 if( fork_head->dpos_irreversible_blocknum <= lib_num )
414 return;
415
416 const auto branch = fork_db.fetch_branch( fork_head->id, fork_head->dpos_irreversible_blocknum );
417 try {
418
419 for( auto bitr = branch.rbegin(); bitr != branch.rend(); ++bitr ) {
422 head = (*bitr);
424 }
425
426 emit( self.irreversible_block, *bitr );
427
428 // blog.append could fail due to failures like running out of space.
429 // Do it before commit so that in case it throws, DB can be rolled back.
430 blog.append( (*bitr)->block );
431
432 db.commit( (*bitr)->block_num );
433 root_id = (*bitr)->id;
434 }
435 } catch( std::exception& ) {
436 if( root_id != fork_db.root()->id ) {
437 fork_db.advance_root( root_id );
438 }
439 throw;
440 }
441
442 //db.commit( fork_head->dpos_irreversible_blocknum ); // redundant
443
444 if( root_id != fork_db.root()->id ) {
445 fork_db.advance_root( root_id );
446 }
447 }
void commit(int64_t revision)
Definition chainbase.cpp:57
const block_id_type & head_id() const
void append(const signed_block_ptr &b)
const signed_block_ptr & head() const
branch_type fetch_branch(const block_id_type &h, uint32_t trim_after_block_num=std::numeric_limits< uint32_t >::max()) const
void advance_root(const block_id_type &id)
void apply_block(const block_state_ptr &bsp, controller::block_status s, const trx_meta_cache_lookup &trx_lookup)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_block_restore_point()

fc::scoped_exit< std::function< void()> > sysio::chain::controller_impl::make_block_restore_point ( )
inline

Definition at line 1082 of file controller.cpp.

1082 {
1083 auto& bb = std::get<building_block>(pending->_block_stage);
1084 auto orig_block_transactions_size = bb._pending_trx_receipts.size();
1085 auto orig_state_transactions_size = bb._pending_trx_metas.size();
1086 auto orig_action_receipt_digests_size = bb._action_receipt_digests.size();
1087
1088 std::function<void()> callback = [this,
1089 orig_block_transactions_size,
1090 orig_state_transactions_size,
1091 orig_action_receipt_digests_size]()
1092 {
1093 auto& bb = std::get<building_block>(pending->_block_stage);
1094 bb._pending_trx_receipts.resize(orig_block_transactions_size);
1095 bb._pending_trx_metas.resize(orig_state_transactions_size);
1096 bb._action_receipt_digests.resize(orig_action_receipt_digests_size);
1097 };
1098
1099 return fc::make_scoped_exit( std::move(callback) );
1100 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ maybe_switch_forks()

void sysio::chain::controller_impl::maybe_switch_forks ( const block_state_ptr & new_head,
controller::block_status s,
const forked_branch_callback & forked_branch_cb,
const trx_meta_cache_lookup & trx_lookup )
inline

end for each block in branch

Definition at line 2229 of file controller.cpp.

2231 {
2232 bool head_changed = true;
2233 if( new_head->header.previous == head->id ) {
2234 try {
2235 apply_block( new_head, s, trx_lookup );
2236 fork_db.mark_valid( new_head );
2237 head = new_head;
2238 } catch ( const std::exception& e ) {
2239 fork_db.remove( new_head->id );
2240 throw;
2241 }
2242 } else if( new_head->id != head->id ) {
2243 auto old_head = head;
2244 ilog("switching forks from ${current_head_id} (block number ${current_head_num}) to ${new_head_id} (block number ${new_head_num})",
2245 ("current_head_id", head->id)("current_head_num", head->block_num)("new_head_id", new_head->id)("new_head_num", new_head->block_num) );
2246
2247 if (auto dm_logger = get_deep_mind_logger()) {
2248 dm_logger->on_switch_forks(head->id, new_head->id);
2249 }
2250
2251 auto branches = fork_db.fetch_branch_from( new_head->id, head->id );
2252
2253 if( branches.second.size() > 0 ) {
2254 for( auto itr = branches.second.begin(); itr != branches.second.end(); ++itr ) {
2255 pop_block();
2256 }
2257 SYS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
2258 "loss of sync between fork_db and chainbase during fork switch" ); // _should_ never fail
2259
2260 if( forked_branch_cb ) forked_branch_cb( branches.second );
2261 }
2262
2263 for( auto ritr = branches.first.rbegin(); ritr != branches.first.rend(); ++ritr ) {
2264 auto except = std::exception_ptr{};
2265 try {
2266 apply_block( *ritr, (*ritr)->is_valid() ? controller::block_status::validated
2267 : controller::block_status::complete, trx_lookup );
2268 fork_db.mark_valid( *ritr );
2269 head = *ritr;
2270 } catch ( const std::bad_alloc& ) {
2271 throw;
2272 } catch ( const boost::interprocess::bad_alloc& ) {
2273 throw;
2274 } catch (const fc::exception& e) {
2275 elog("exception thrown while switching forks ${e}", ("e", e.to_detail_string()));
2276 except = std::current_exception();
2277 } catch (const std::exception& e) {
2278 elog("exception thrown while switching forks ${e}", ("e", e.what()));
2279 except = std::current_exception();
2280 }
2281
2282 if( except ) {
2283 // ritr currently points to the block that threw
2284 // Remove the block that threw and all forks built off it.
2285 fork_db.remove( (*ritr)->id );
2286
2287 // pop all blocks from the bad fork, discarding their transactions
2288 // ritr base is a forward itr to the last block successfully applied
2289 auto applied_itr = ritr.base();
2290 for( auto itr = applied_itr; itr != branches.first.end(); ++itr ) {
2291 pop_block();
2292 }
2293 SYS_ASSERT( self.head_block_id() == branches.second.back()->header.previous, fork_database_exception,
2294 "loss of sync between fork_db and chainbase during fork switch reversal" ); // _should_ never fail
2295
2296 // re-apply good blocks
2297 for( auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr ) {
2298 apply_block( *ritr, controller::block_status::validated /* we previously validated these blocks*/, trx_lookup );
2299 head = *ritr;
2300 }
2301 std::rethrow_exception(except);
2302 } // end if exception
2303 }
2304
2305 ilog("successfully switched fork to new head ${new_head_id}", ("new_head_id", new_head->id));
2306 } else {
2307 head_changed = false;
2308 }
2309
2310 if( head_changed )
2312
2313 }
@ validated
this is a complete block signed by a valid producer and has been previously applied by this node and ...
void remove(const block_id_type &id)
fetch_branch_from_impl
pair< branch_type, branch_type > fetch_branch_from(const block_id_type &first, const block_id_type &second) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_activation()

void sysio::chain::controller_impl::on_activation ( )
Here is the caller graph for this function:

◆ pop_block()

void sysio::chain::controller_impl::pop_block ( )
inline

Definition at line 259 of file controller.cpp.

259 {
260 auto prev = fork_db.get_block( head->header.previous );
261
262 if( !prev ) {
263 SYS_ASSERT( fork_db.root()->id == head->header.previous, block_validate_exception, "attempt to pop beyond last irreversible block" );
264 prev = fork_db.root();
265 }
266
268 SYS_ASSERT( head->block, block_validate_exception, "attempting to pop a block that was sparsely loaded from a snapshot");
269 }
270
271 head = prev;
272
273 db.undo();
274
275 protocol_features.popped_blocks_to( prev->block_num );
276 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_block()

void sysio::chain::controller_impl::push_block ( const block_state_ptr & bsp,
const forked_branch_callback & forked_branch_cb,
const trx_meta_cache_lookup & trx_lookup )
inline

Definition at line 2133 of file controller.cpp.

2136 {
2138 SYS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block");
2139
2140 auto reset_prod_light_validation = fc::make_scoped_exit([old_value=trusted_producer_light_validation, this]() {
2142 });
2143 try {
2144 SYS_ASSERT( bsp, block_validate_exception, "null block" );
2145 const auto& b = bsp->block;
2146
2148 ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
2149 shutdown();
2150 return;
2151 }
2152
2154
2155 fork_db.add( bsp );
2156
2157 if (self.is_trusted_producer(b->producer)) {
2159 };
2160
2162
2164 maybe_switch_forks( fork_db.pending_head(), s, forked_branch_cb, trx_lookup );
2165 } else {
2167 }
2168
2170 }
bool is_trusted_producer(const account_name &producer) const
signal< void(const signed_block_ptr &)> pre_accepted_block
#define FC_LOG_AND_RETHROW()
std::function< void()> shutdown
Here is the call graph for this function:

◆ push_receipt()

template<typename T >
const transaction_receipt & sysio::chain::controller_impl::push_receipt ( const T & trx,
transaction_receipt_header::status_enum status,
uint64_t cpu_usage_us,
uint64_t net_usage )
inline

Adds the transaction receipt to the pending block and returns it.

Definition at line 1437 of file controller.cpp.

1438 {
1439 uint64_t net_usage_words = net_usage / 8;
1440 SYS_ASSERT( net_usage_words*8 == net_usage, transaction_exception, "net_usage is not divisible by 8" );
1441 auto& receipts = std::get<building_block>(pending->_block_stage)._pending_trx_receipts;
1442 receipts.emplace_back( trx );
1443 transaction_receipt& r = receipts.back();
1444 r.cpu_usage_us = cpu_usage_us;
1445 r.net_usage_words = net_usage_words;
1446 r.status = status;
1447 return r;
1448 }
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
Here is the caller graph for this function:

◆ push_scheduled_transaction() [1/2]

transaction_trace_ptr sysio::chain::controller_impl::push_scheduled_transaction ( const generated_transaction_object & gto,
fc::time_point block_deadline,
fc::microseconds max_transaction_time,
uint32_t billed_cpu_time_us,
bool explicit_billed_cpu_time = false )
inline

Definition at line 1228 of file controller.cpp.

1231 { try {
1232
1233 const bool validating = !self.is_producing_block();
1234 SYS_ASSERT( !validating || explicit_billed_cpu_time, transaction_exception, "validating requires explicit billing" );
1235
1236 maybe_session undo_session;
1237 if ( !self.skip_db_sessions() )
1238 undo_session = maybe_session(db);
1239
1240 auto gtrx = generated_transaction(gto);
1241
1242 // remove the generated transaction object after making a copy
1243 // this will ensure that anything which affects the GTO multi-index-container will not invalidate
1244 // data we need to successfully retire this transaction.
1245 //
1246 // IF the transaction FAILs in a subjective way, `undo_session` should expire without being squashed
1247 // resulting in the GTO being restored and available for a future block to retire.
1248 int64_t trx_removal_ram_delta = remove_scheduled_transaction(gto);
1249
1250 fc::datastream<const char*> ds( gtrx.packed_trx.data(), gtrx.packed_trx.size() );
1251
1252 SYS_ASSERT( gtrx.delay_until <= self.pending_block_time(), transaction_exception, "this transaction isn't ready",
1253 ("gtrx.delay_until",gtrx.delay_until)("pbt",self.pending_block_time()) );
1254
1255 signed_transaction dtrx;
1256 fc::raw::unpack(ds,static_cast<transaction&>(dtrx) );
1258 transaction_metadata::create_no_recover_keys( std::make_shared<packed_transaction>( std::move(dtrx) ),
1260 trx->accepted = true;
1261
1263 if( gtrx.expiration < self.pending_block_time() ) {
1264 trace = std::make_shared<transaction_trace>();
1265 trace->id = gtrx.trx_id;
1266 trace->block_num = self.head_block_num() + 1;
1267 trace->block_time = self.pending_block_time();
1268 trace->producer_block_id = self.pending_producer_block_id();
1269 trace->scheduled = true;
1270 trace->receipt = push_receipt( gtrx.trx_id, transaction_receipt::expired, billed_cpu_time_us, 0 ); // expire the transaction
1271 trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
1274 emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
1275 undo_session.squash();
1276 return trace;
1277 }
1278
1279 auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){
1280 in_trx_requiring_checks = old_value;
1281 });
1283
1284 uint32_t cpu_time_to_bill_us = billed_cpu_time_us;
1285
1286 transaction_checktime_timer trx_timer(timer);
1287 transaction_context trx_context( self, *trx->packed_trx(), std::move(trx_timer) );
1288 trx_context.leeway = fc::microseconds(0); // avoid stealing cpu resource
1289 trx_context.block_deadline = block_deadline;
1290 trx_context.max_transaction_time_subjective = max_transaction_time;
1291 trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
1292 trx_context.billed_cpu_time_us = billed_cpu_time_us;
1293 trx_context.enforce_whiteblacklist = gtrx.sender.empty() ? true : !sender_avoids_whitelist_blacklist_enforcement( gtrx.sender );
1294 trace = trx_context.trace;
1295
1296 auto handle_exception = [&](const auto& e)
1297 {
1298 cpu_time_to_bill_us = trx_context.update_billed_cpu_time( fc::time_point::now() );
1299 trace->error_code = controller::convert_exception_to_error_code( e );
1300 trace->except = e;
1301 trace->except_ptr = std::current_exception();
1302 trace->elapsed = fc::time_point::now() - trx_context.start;
1303
1304 if (auto dm_logger = get_deep_mind_logger()) {
1305 dm_logger->on_fail_deferred();
1306 }
1307 };
1308
1309 try {
1310 trx_context.init_for_deferred_trx( gtrx.published );
1311
1312 if( trx_context.enforce_whiteblacklist && pending->_block_status == controller::block_status::incomplete ) {
1313 flat_set<account_name> actors;
1314 for( const auto& act : trx->packed_trx()->get_transaction().actions ) {
1315 for( const auto& auth : act.authorization ) {
1316 actors.insert( auth.actor );
1317 }
1318 }
1319 check_actor_list( actors );
1320 }
1321
1322 trx_context.exec();
1323 trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
1324
1325 auto restore = make_block_restore_point();
1326
1327 trace->receipt = push_receipt( gtrx.trx_id,
1329 trx_context.billed_cpu_time_us,
1330 trace->net_usage );
1331
1332 fc::move_append( std::get<building_block>(pending->_block_stage)._action_receipt_digests,
1333 std::move(trx_context.executed_action_receipt_digests) );
1334
1335 trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
1336
1339 emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
1340
1341 trx_context.squash();
1342 undo_session.squash();
1343
1344 restore.cancel();
1345
1346 return trace;
1347 } catch( const disallowed_transaction_extensions_bad_block_exception& ) {
1348 throw;
1349 } catch( const protocol_feature_bad_block_exception& ) {
1350 throw;
1351 } catch ( const std::bad_alloc& ) {
1352 throw;
1353 } catch ( const boost::interprocess::bad_alloc& ) {
1354 throw;
1355 } catch( const fc::exception& e ) {
1356 handle_exception(e);
1357 } catch ( const std::exception& e) {
1359 handle_exception(wrapper);
1360 }
1361
1362 trx_context.undo();
1363
1364 // Only subjective OR soft OR hard failure logic below:
1365
1366 if( gtrx.sender != account_name() && !(validating ? failure_is_subjective(*trace->except) : scheduled_failure_is_subjective(*trace->except))) {
1367 // Attempt error handling for the generated transaction.
1368
1369 auto error_trace = apply_onerror( gtrx, block_deadline, max_transaction_time, trx_context.pseudo_start,
1370 cpu_time_to_bill_us, billed_cpu_time_us, explicit_billed_cpu_time,
1371 trx_context.enforce_whiteblacklist );
1372 error_trace->failed_dtrx_trace = trace;
1373 trace = error_trace;
1374 if( !trace->except_ptr ) {
1375 trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
1378 emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
1379 undo_session.squash();
1380 return trace;
1381 }
1382 trace->elapsed = fc::time_point::now() - trx_context.start;
1383 }
1384
1385 // Only subjective OR hard failure logic below:
1386
1387 // subjectivity changes based on producing vs validating
1388 bool subjective = false;
1389 if (validating) {
1390 subjective = failure_is_subjective(*trace->except);
1391 } else {
1392 subjective = scheduled_failure_is_subjective(*trace->except);
1393 }
1394
1395 if ( !subjective ) {
1396 // hard failure logic
1397
1398 if( !validating ) {
1400 rl.update_account_usage( trx_context.bill_to_accounts, block_timestamp_type(self.pending_block_time()).slot );
1401 int64_t account_cpu_limit = 0;
1402 std::tie( std::ignore, account_cpu_limit, std::ignore, std::ignore ) = trx_context.max_bandwidth_billed_accounts_can_pay( true );
1403
1404 uint32_t limited_cpu_time_to_bill_us = static_cast<uint32_t>( std::min(
1405 std::min( static_cast<int64_t>(cpu_time_to_bill_us), account_cpu_limit ),
1406 trx_context.initial_objective_duration_limit.count() ) );
1407 SYS_ASSERT( !explicit_billed_cpu_time || (cpu_time_to_bill_us == limited_cpu_time_to_bill_us),
1408 transaction_exception, "cpu to bill ${cpu} != limited ${limit}", ("cpu", cpu_time_to_bill_us)("limit", limited_cpu_time_to_bill_us) );
1409 cpu_time_to_bill_us = limited_cpu_time_to_bill_us;
1410 }
1411
1412 resource_limits.add_transaction_usage( trx_context.bill_to_accounts, cpu_time_to_bill_us, 0,
1413 block_timestamp_type(self.pending_block_time()).slot ); // Should never fail
1414
1415 trace->receipt = push_receipt(gtrx.trx_id, transaction_receipt::hard_fail, cpu_time_to_bill_us, 0);
1416 trace->account_ram_delta = account_delta( gtrx.payer, trx_removal_ram_delta );
1417
1420 emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
1421
1422 undo_session.squash();
1423 } else {
1426 emit( self.applied_transaction, std::tie(trace, trx->packed_trx()) );
1427 }
1428
1429 return trace;
signal< void(const transaction_metadata_ptr &)> accepted_transaction
bool is_producing_block() const
std::optional< block_id_type > pending_producer_block_id() const
@ incomplete
this is an incomplete block (either being produced by a producer or speculatively produced by a node)
signal< void(std::tuple< const transaction_trace_ptr &, const packed_transaction_ptr & >)> applied_transaction
resource_limits_manager & get_mutable_resource_limits_manager()
void update_account_usage(const flat_set< account_name > &accounts, uint32_t ordinal)
void add_transaction_usage(const flat_set< account_name > &accounts, uint64_t cpu_usage, uint64_t net_usage, uint32_t ordinal)
static const Segment ds(Segment::ds)
name account_name
Definition types.hpp:120
int64_t remove_scheduled_transaction(const generated_transaction_object &gto)
void dmlog_applied_transaction(const transaction_trace_ptr &t)
transaction_trace_ptr apply_onerror(const generated_transaction &gtrx, fc::time_point block_deadline, fc::microseconds max_transaction_time, fc::time_point start, uint32_t &cpu_time_to_bill_us, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time=false, bool enforce_whiteblacklist=true)
bool in_trx_requiring_checks
if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
bool scheduled_failure_is_subjective(const fc::exception &e) const
void check_actor_list(const flat_set< account_name > &actors) const
bool failure_is_subjective(const fc::exception &e) const
bool sender_avoids_whitelist_blacklist_enforcement(account_name sender) const
@ executed
succeed, no error handler executed
Definition block.hpp:14
@ expired
transaction expired and storage space refuned to user
Definition block.hpp:18
Here is the call graph for this function:

◆ push_scheduled_transaction() [2/2]

transaction_trace_ptr sysio::chain::controller_impl::push_scheduled_transaction ( const transaction_id_type & trxid,
fc::time_point block_deadline,
fc::microseconds max_transaction_time,
uint32_t billed_cpu_time_us,
bool explicit_billed_cpu_time = false )
inline

Definition at line 1218 of file controller.cpp.

1221 {
1222 const auto& idx = db.get_index<generated_transaction_multi_index,by_trx_id>();
1223 auto itr = idx.find( trxid );
1224 SYS_ASSERT( itr != idx.end(), unknown_transaction_exception, "unknown transaction" );
1225 return push_scheduled_transaction( *itr, block_deadline, max_transaction_time, billed_cpu_time_us, explicit_billed_cpu_time );
1226 }
const generic_index< MultiIndexType > & get_index() const
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:

◆ push_transaction()

transaction_trace_ptr sysio::chain::controller_impl::push_transaction ( const transaction_metadata_ptr & trx,
fc::time_point block_deadline,
fc::microseconds max_transaction_time,
uint32_t billed_cpu_time_us,
bool explicit_billed_cpu_time,
int64_t subjective_cpu_bill_us )
inline

This is the entry point for new transactions to the block state. It will check authorization and determine whether to execute it now or to delay it. Lastly it inserts a transaction receipt into the pending block.

Definition at line 1455 of file controller.cpp.

1461 {
1462 SYS_ASSERT(block_deadline != fc::time_point(), transaction_exception, "deadline cannot be uninitialized");
1463
1465 try {
1466 auto start = fc::time_point::now();
1467 const bool check_auth = !self.skip_auth_check() && !trx->implicit;
1468 const fc::microseconds sig_cpu_usage = trx->signature_cpu_usage();
1469
1470 if( !explicit_billed_cpu_time ) {
1471 fc::microseconds already_consumed_time( SYS_PERCENT(sig_cpu_usage.count(), conf.sig_cpu_bill_pct) );
1472
1473 if( start.time_since_epoch() < already_consumed_time ) {
1475 } else {
1476 start -= already_consumed_time;
1477 }
1478 }
1479
1480 const signed_transaction& trn = trx->packed_trx()->get_signed_transaction();
1481 transaction_checktime_timer trx_timer(timer);
1482 transaction_context trx_context(self, *trx->packed_trx(), std::move(trx_timer), start, trx->read_only);
1484 trx_context.leeway = *subjective_cpu_leeway;
1485 }
1486 trx_context.block_deadline = block_deadline;
1487 trx_context.max_transaction_time_subjective = max_transaction_time;
1488 trx_context.explicit_billed_cpu_time = explicit_billed_cpu_time;
1489 trx_context.billed_cpu_time_us = billed_cpu_time_us;
1490 trx_context.subjective_cpu_bill_us = subjective_cpu_bill_us;
1491 trace = trx_context.trace;
1492
1493 auto handle_exception =[&](const auto& e)
1494 {
1495 trace->error_code = controller::convert_exception_to_error_code( e );
1496 trace->except = e;
1497 trace->except_ptr = std::current_exception();
1498 trace->elapsed = fc::time_point::now() - trx_context.start;
1499 };
1500
1501 try {
1502 if( trx->implicit ) {
1503 trx_context.init_for_implicit_trx();
1504 trx_context.enforce_whiteblacklist = false;
1505 } else {
1506 trx_context.init_for_input_trx( trx->packed_trx()->get_unprunable_size(),
1507 trx->packed_trx()->get_prunable_size() );
1508 }
1509
1510 trx_context.delay = fc::seconds(trn.delay_sec);
1511
1512 if( check_auth ) {
1514 trn.actions,
1515 trx->recovered_keys(),
1516 {},
1517 trx_context.delay,
1518 [&trx_context](){ trx_context.checktime(); },
1519 false,
1520 trx->read_only
1521 );
1522 }
1523 trx_context.exec();
1524 trx_context.finalize(); // Automatically rounds up network and CPU usage in trace and bills payers if successful
1525
1526 auto restore = make_block_restore_point();
1527
1528 if (!trx->implicit) {
1529 transaction_receipt::status_enum s = (trx_context.delay == fc::seconds(0))
1531 : transaction_receipt::delayed;
1532 trace->receipt = push_receipt(*trx->packed_trx(), s, trx_context.billed_cpu_time_us, trace->net_usage);
1533 trx->billed_cpu_time_us = trx_context.billed_cpu_time_us;
1534 std::get<building_block>(pending->_block_stage)._pending_trx_metas.emplace_back(trx);
1535 } else {
1536 transaction_receipt_header r;
1538 r.cpu_usage_us = trx_context.billed_cpu_time_us;
1539 r.net_usage_words = trace->net_usage / 8;
1540 trace->receipt = r;
1541 }
1542
1543 fc::move_append( std::get<building_block>(pending->_block_stage)._action_receipt_digests,
1544 std::move(trx_context.executed_action_receipt_digests) );
1545
1546 // call the accept signal but only once for this transaction
1547 if (!trx->read_only) {
1548 if (!trx->accepted) {
1549 trx->accepted = true;
1551 }
1552
1554 emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
1555 }
1556
1557
1558 if ( (read_mode != db_read_mode::SPECULATIVE && pending->_block_status == controller::block_status::incomplete) || trx->read_only ) {
1559 //this may happen automatically in destructor, but I prefer make it more explicit
1560 trx_context.undo();
1561 } else {
1562 restore.cancel();
1563 trx_context.squash();
1564 }
1565
1566 return trace;
1567 } catch( const disallowed_transaction_extensions_bad_block_exception& ) {
1568 throw;
1569 } catch( const protocol_feature_bad_block_exception& ) {
1570 throw;
1571 } catch ( const std::bad_alloc& ) {
1572 throw;
1573 } catch ( const boost::interprocess::bad_alloc& ) {
1574 throw;
1575 } catch (const fc::exception& e) {
1576 handle_exception(e);
1577 } catch (const std::exception& e) {
1579 handle_exception(wrapper);
1580 }
1581
1582 if (!trx->read_only) {
1585 emit(self.applied_transaction, std::tie(trace, trx->packed_trx()));
1586 }
1587
1588 return trace;
1589 } FC_CAPTURE_AND_RETHROW((trace))
1590 }
constexpr int64_t count() const
Definition time.hpp:26
void check_authorization(const vector< action > &actions, const flat_set< public_key_type > &provided_keys, const flat_set< permission_level > &provided_permissions=flat_set< permission_level >(), fc::microseconds provided_delay=fc::microseconds(0), const std::function< void()> &checktime=std::function< void()>(), bool allow_unused_keys=false, bool check_but_dont_fail=false, const flat_set< permission_level > &satisfied_authorizations=flat_set< permission_level >()) const
Check authorizations of a vector of actions with provided keys, permission levels,...
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
std::optional< fc::microseconds > subjective_cpu_leeway
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_contract_tables_from_snapshot()

void sysio::chain::controller_impl::read_contract_tables_from_snapshot ( const snapshot_reader_ptr & snapshot)
inline

Definition at line 773 of file controller.cpp.

773 {
774 snapshot->read_section("contract_tables", [this]( auto& section ) {
775 bool more = !section.empty();
776 while (more) {
777 // read the row for the table
779 index_utils<table_id_multi_index>::create(db, [this, &section, &t_id](auto& row) {
780 section.read_row(row, db);
781 t_id = row.id;
782 });
783
784 // read the size and data rows for each type of table
785 contract_database_index_set::walk_indices([this, &section, &t_id, &more](auto utils) {
786 using utils_t = decltype(utils);
787
788 unsigned_int size;
789 more = section.read_row(size, db);
790
791 for (size_t idx = 0; idx < size.value; idx++) {
792 utils_t::create(db, [this, &section, &more, &t_id](auto& row) {
793 row.t_id = t_id;
794 more = section.read_row(row, db);
795 });
796 }
797 });
798 }
799 });
800 }
static void create(chainbase::database &db, F cons)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ read_from_snapshot()

void sysio::chain::controller_impl::read_from_snapshot ( const snapshot_reader_ptr & snapshot,
uint32_t blog_start,
uint32_t blog_end )
inline

load and upgrade the block header state

Definition at line 853 of file controller.cpp.

853 {
854 chain_snapshot_header header;
855 snapshot->read_section<chain_snapshot_header>([this, &header]( auto &section ){
856 section.read_row(header, db);
857 header.validate();
858 });
859
860 {
861 block_header_state head_header_state;
862 using v2 = legacy::snapshot_block_header_state_v2;
863
864 if (std::clamp(header.version, v2::minimum_version, v2::maximum_version) == header.version ) {
865 snapshot->read_section<block_state>([this, &head_header_state]( auto &section ) {
866 legacy::snapshot_block_header_state_v2 legacy_header_state;
867 section.read_row(legacy_header_state, db);
868 head_header_state = block_header_state(std::move(legacy_header_state));
869 });
870 } else {
871 snapshot->read_section<block_state>([this,&head_header_state]( auto &section ){
872 section.read_row(head_header_state, db);
873 });
874 }
875
876 snapshot_head_block = head_header_state.block_num;
877 SYS_ASSERT( blog_start <= (snapshot_head_block + 1) && snapshot_head_block <= blog_end,
878 block_log_exception,
879 "Block log is provided with snapshot but does not contain the head block from the snapshot nor a block right after it",
880 ("snapshot_head_block", snapshot_head_block)
881 ("block_log_first_num", blog_start)
882 ("block_log_last_num", blog_end)
883 );
884
885 head = std::make_shared<block_state>();
886 static_cast<block_header_state&>(*head) = head_header_state;
887 }
888
889 controller_index_set::walk_indices([this, &snapshot, &header]( auto utils ){
890 using value_t = typename decltype(utils)::index_t::value_type;
891
892 // skip the table_id_object as its inlined with contract tables section
893 if (std::is_same<value_t, table_id_object>::value) {
894 return;
895 }
896
897 // skip the database_header as it is only relevant to in-memory database
898 if (std::is_same<value_t, database_header_object>::value) {
899 return;
900 }
901
902 // special case for in-place upgrade of global_property_object
903 if (std::is_same<value_t, global_property_object>::value) {
904 using v2 = legacy::snapshot_global_property_object_v2;
905 using v3 = legacy::snapshot_global_property_object_v3;
906 using v4 = legacy::snapshot_global_property_object_v4;
907
908 if (std::clamp(header.version, v2::minimum_version, v2::maximum_version) == header.version ) {
909 std::optional<genesis_state> genesis = extract_legacy_genesis_state(*snapshot, header.version);
910 SYS_ASSERT( genesis, snapshot_exception,
911 "Snapshot indicates chain_snapshot_header version 2, but does not contain a genesis_state. "
912 "It must be corrupted.");
913 snapshot->read_section<global_property_object>([&db=this->db,gs_chain_id=genesis->compute_chain_id()]( auto &section ) {
914 v2 legacy_global_properties;
915 section.read_row(legacy_global_properties, db);
916
917 db.create<global_property_object>([&legacy_global_properties,&gs_chain_id](auto& gpo ){
918 gpo.initalize_from(legacy_global_properties, gs_chain_id, kv_database_config{},
920 });
921 });
922 return; // early out to avoid default processing
923 }
924
925 if (std::clamp(header.version, v3::minimum_version, v3::maximum_version) == header.version ) {
926 snapshot->read_section<global_property_object>([&db=this->db]( auto &section ) {
927 v3 legacy_global_properties;
928 section.read_row(legacy_global_properties, db);
929
930 db.create<global_property_object>([&legacy_global_properties](auto& gpo ){
931 gpo.initalize_from(legacy_global_properties, kv_database_config{},
933 });
934 });
935 return; // early out to avoid default processing
936 }
937
938 if (std::clamp(header.version, v4::minimum_version, v4::maximum_version) == header.version) {
939 snapshot->read_section<global_property_object>([&db = this->db](auto& section) {
940 v4 legacy_global_properties;
941 section.read_row(legacy_global_properties, db);
942
943 db.create<global_property_object>([&legacy_global_properties](auto& gpo) {
944 gpo.initalize_from(legacy_global_properties);
945 });
946 });
947 return; // early out to avoid default processing
948 }
949 }
950
951 snapshot->read_section<value_t>([this]( auto& section ) {
952 bool more = !section.empty();
953 while(more) {
954 decltype(utils)::create(db, [this, &section, &more]( auto &row ) {
955 more = section.read_row(row, db);
956 });
957 }
958 });
959 });
960
962
965
966 db.set_revision( head->block_num );
967 db.create<database_header_object>([](const auto& header){
968 // nothing to do
969 });
970
971 const auto& gpo = db.get<global_property_object>();
972 SYS_ASSERT( gpo.chain_id == chain_id, chain_id_type_exception,
973 "chain ID in snapshot (${snapshot_chain_id}) does not match the chain ID that controller was constructed with (${controller_chain_id})",
974 ("snapshot_chain_id", gpo.chain_id)("controller_chain_id", chain_id)
975 );
976 }
void read_from_snapshot(const snapshot_reader_ptr &snapshot)
void read_from_snapshot(const snapshot_reader_ptr &snapshot)
static std::optional< genesis_state > extract_legacy_genesis_state(snapshot_reader &snapshot, uint32_t version)
void read_contract_tables_from_snapshot(const snapshot_reader_ptr &snapshot)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_scheduled_transaction()

int64_t sysio::chain::controller_impl::remove_scheduled_transaction ( const generated_transaction_object & gto)
inline

Definition at line 1180 of file controller.cpp.

1180 {
1181 if (auto dm_logger = get_deep_mind_logger()) {
1182 dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", gto.id)), "deferred_trx", "remove", "deferred_trx_removed");
1183 }
1184
1185 int64_t ram_delta = -(config::billable_size_v<generated_transaction_object> + gto.packed_trx.size());
1186 resource_limits.add_pending_ram_usage( gto.payer, ram_delta );
1187 // No need to verify_account_ram_usage since we are only reducing memory
1188
1189 db.remove( gto );
1190 return ram_delta;
1191 }
void remove(const ObjectType &obj)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ replay()

void sysio::chain::controller_impl::replay ( std::function< bool()> check_shutdown)
inline

Definition at line 475 of file controller.cpp.

475 {
476 if( !blog.head() && !fork_db.root() ) {
477 fork_db.reset( *head );
478 return;
479 }
480
481 auto blog_head = blog.head();
482 replaying = true;
483 auto start_block_num = head->block_num + 1;
484 auto start = fc::time_point::now();
485
486 std::exception_ptr except_ptr;
487
488 if( blog_head && start_block_num <= blog_head->block_num() ) {
489 ilog( "existing block log, attempting to replay from ${s} to ${n} blocks",
490 ("s", start_block_num)("n", blog_head->block_num()) );
491 try {
492 while( auto next = blog.read_block_by_num( head->block_num + 1 ) ) {
494 if( check_shutdown() ) break;
495 if( next->block_num() % 500 == 0 ) {
496 ilog( "${n} of ${head}", ("n", next->block_num())("head", blog_head->block_num()) );
497 }
498 }
499 } catch( const database_guard_exception& e ) {
500 except_ptr = std::current_exception();
501 }
502 ilog( "${n} irreversible blocks replayed", ("n", 1 + head->block_num - start_block_num) );
503
504 auto pending_head = fork_db.pending_head();
505 if( pending_head ) {
506 ilog( "fork database head ${h}, root ${r}", ("h", pending_head->block_num)( "r", fork_db.root()->block_num ) );
507 if( pending_head->block_num < head->block_num || head->block_num < fork_db.root()->block_num ) {
508 ilog( "resetting fork database with new last irreversible block as the new root: ${id}", ("id", head->id) );
509 fork_db.reset( *head );
510 } else if( head->block_num != fork_db.root()->block_num ) {
511 auto new_root = fork_db.search_on_branch( pending_head->id, head->block_num );
513 "unexpected error: could not find new LIB in fork database" );
514 ilog( "advancing fork database root to new last irreversible block within existing fork database: ${id}",
515 ("id", new_root->id) );
516 fork_db.mark_valid( new_root );
517 fork_db.advance_root( new_root->id );
518 }
519 }
520
521 // if the irreverible log is played without undo sessions enabled, we need to sync the
522 // revision ordinal to the appropriate expected value here.
524 db.set_revision( head->block_num );
525 } else {
526 ilog( "no irreversible blocks need to be replayed" );
527 }
528
529 if( !except_ptr && !check_shutdown() && fork_db.head() ) {
530 auto head_block_num = head->block_num;
531 auto branch = fork_db.fetch_branch( fork_db.head()->id );
532 int rev = 0;
533 for( auto i = branch.rbegin(); i != branch.rend(); ++i ) {
534 if( check_shutdown() ) break;
535 if( (*i)->block_num <= head_block_num ) continue;
536 ++rev;
538 }
539 ilog( "${n} reversible blocks replayed", ("n",rev) );
540 }
541
542 if( !fork_db.head() ) {
543 fork_db.reset( *head );
544 }
545
546 auto end = fc::time_point::now();
547 ilog( "replayed ${n} blocks in ${duration} seconds, ${mspb} ms/block",
548 ("n", head->block_num + 1 - start_block_num)("duration", (end-start).count()/1000000)
549 ("mspb", ((end-start).count()/1000.0)/(head->block_num-start_block_num)) );
550 replaying = false;
551
552 if( except_ptr ) {
553 std::rethrow_exception( except_ptr );
554 }
555 }
signed_block_ptr read_block_by_num(uint32_t block_num) const
@ irreversible
this block has already been applied before by this node and is considered irreversible
block_state_ptr search_on_branch(const block_id_type &h, uint32_t block_num) const
void reset(const block_header_state &root_bhs)
uint32_t next(octet_iterator &it, octet_iterator end)
Definition checked.h:137
void replay_push_block(const signed_block_ptr &b, controller::block_status s)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ replay_push_block()

void sysio::chain::controller_impl::replay_push_block ( const signed_block_ptr & b,
controller::block_status s )
inline

Definition at line 2172 of file controller.cpp.

2172 {
2174
2175 SYS_ASSERT(!pending, block_validate_exception, "it is not valid to push a block when there is a pending block");
2176
2177 try {
2178 SYS_ASSERT( b, block_validate_exception, "trying to push empty block" );
2180 block_validate_exception, "invalid block status for replay" );
2181
2183 ilog("Reached configured maximum block ${num}; terminating", ("num", conf.terminate_at_block) );
2184 shutdown();
2185 return;
2186 }
2187
2189 const bool skip_validate_signee = !conf.force_all_checks;
2190
2191 auto bsp = std::make_shared<block_state>(
2192 *head,
2193 b,
2195 [this]( block_timestamp_type timestamp,
2196 const flat_set<digest_type>& cur_features,
2197 const vector<digest_type>& new_features )
2198 { check_protocol_features( timestamp, cur_features, new_features ); },
2199 skip_validate_signee
2200 );
2201
2203 fork_db.add( bsp, true );
2204 }
2205
2207
2210 head = bsp;
2211
2212 // On replay, log_irreversible is not called and so no irreversible_block signal is emitted.
2213 // So emit it explicitly here.
2215
2216 if (!self.skip_db_sessions(s)) {
2217 db.commit(bsp->block_num);
2218 }
2219
2220 } else {
2222 "invariant failure: cannot replay reversible blocks while in irreversible mode" );
2224 }
2225
2227 }
void validate_db_available_size() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ report_block_header_diff()

void sysio::chain::controller_impl::report_block_header_diff ( const block_header & b,
const block_header & ab )
inline

Definition at line 1927 of file controller.cpp.

1927 {
1928
1929#define SYS_REPORT(DESC,A,B) \
1930 if( A != B ) { \
1931 elog("${desc}: ${bv} != ${abv}", ("desc", DESC)("bv", A)("abv", B)); \
1932 }
1933
1934 SYS_REPORT( "timestamp", b.timestamp, ab.timestamp )
1935 SYS_REPORT( "producer", b.producer, ab.producer )
1936 SYS_REPORT( "confirmed", b.confirmed, ab.confirmed )
1937 SYS_REPORT( "previous", b.previous, ab.previous )
1938 SYS_REPORT( "transaction_mroot", b.transaction_mroot, ab.transaction_mroot )
1939 SYS_REPORT( "action_mroot", b.action_mroot, ab.action_mroot )
1940 SYS_REPORT( "schedule_version", b.schedule_version, ab.schedule_version )
1941 SYS_REPORT( "new_producers", b.new_producers, ab.new_producers )
1942 SYS_REPORT( "header_extensions", b.header_extensions, ab.header_extensions )
1943
1944#undef SYS_REPORT
1945 }
#define SYS_REPORT(DESC, A, B)
Here is the caller graph for this function:

◆ scheduled_failure_is_subjective()

bool sysio::chain::controller_impl::scheduled_failure_is_subjective ( const fc::exception & e) const
inline

Definition at line 1212 of file controller.cpp.

1212 {
1213 auto code = e.code();
1214 return (code == tx_cpu_usage_exceeded::code_value)
1216 }
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sender_avoids_whitelist_blacklist_enforcement()

bool sysio::chain::controller_impl::sender_avoids_whitelist_blacklist_enforcement ( account_name sender) const
inline

Definition at line 2397 of file controller.cpp.

2397 {
2398 if( conf.sender_bypass_whiteblacklist.size() > 0 &&
2400 {
2401 return true;
2402 }
2403
2404 return false;
2405 }
flat_set< account_name > sender_bypass_whiteblacklist
Here is the caller graph for this function:

◆ set_activation_handler()

void sysio::chain::controller_impl::set_activation_handler ( )
inline

Definition at line 282 of file controller.cpp.

282 {
284 SYS_ASSERT( res.second, misc_exception, "attempting to set activation handler twice" );
285 }
unordered_map< builtin_protocol_feature_t, std::function< void(controller_impl &)>, enum_hash< builtin_protocol_feature_t > > protocol_feature_activation_handlers
Here is the call graph for this function:

◆ set_apply_handler()

void sysio::chain::controller_impl::set_apply_handler ( account_name receiver,
account_name contract,
action_name action,
apply_handler v )
inline

Definition at line 293 of file controller.cpp.

293 {
294 apply_handlers[receiver][make_pair(contract,action)] = v;
295 }
map< account_name, map< handler_key, apply_handler > > apply_handlers

◆ start_block()

void sysio::chain::controller_impl::start_block ( block_timestamp_type when,
uint16_t confirm_block_count,
const vector< digest_type > & new_protocol_feature_activations,
controller::block_status s,
const std::optional< block_id_type > & producer_block_id,
const fc::time_point & deadline )
inline

Definition at line 1592 of file controller.cpp.

1598 {
1599 SYS_ASSERT( !pending, block_validate_exception, "pending block already exists" );
1600
1601 emit( self.block_start, head->block_num + 1 );
1602
1603 if (auto dm_logger = get_deep_mind_logger()) {
1604 // The head block represents the block just before this one that is about to start, so add 1 to get this block num
1605 dm_logger->on_start_block(head->block_num + 1);
1606 }
1607
1608 auto guard_pending = fc::make_scoped_exit([this, head_block_num=head->block_num](){
1609 protocol_features.popped_blocks_to( head_block_num );
1610 pending.reset();
1611 });
1612
1613 if (!self.skip_db_sessions(s)) {
1614 SYS_ASSERT( db.revision() == head->block_num, database_exception, "db revision is not on par with head block",
1615 ("db.revision()", db.revision())("controller_head_block", head->block_num)("fork_db_head_block", fork_db.head()->block_num) );
1616
1617 pending.emplace( maybe_session(db), *head, when, confirm_block_count, new_protocol_feature_activations );
1618 } else {
1619 pending.emplace( maybe_session(), *head, when, confirm_block_count, new_protocol_feature_activations );
1620 }
1621
1622 pending->_block_status = s;
1623 pending->_producer_block_id = producer_block_id;
1624
1625 auto& bb = std::get<building_block>(pending->_block_stage);
1626 const auto& pbhs = bb._pending_block_header_state;
1627
1628 // modify state of speculative block only if we are in speculative read mode (otherwise we need clean state for head or read-only modes)
1630 {
1631 const auto& pso = db.get<protocol_state_object>();
1632
1633 auto num_preactivated_protocol_features = pso.preactivated_protocol_features.size();
1634 bool handled_all_preactivated_features = (num_preactivated_protocol_features == 0);
1635
1636 if( new_protocol_feature_activations.size() > 0 ) {
1637 flat_map<digest_type, bool> activated_protocol_features;
1638 activated_protocol_features.reserve( std::max( num_preactivated_protocol_features,
1639 new_protocol_feature_activations.size() ) );
1640 for( const auto& feature_digest : pso.preactivated_protocol_features ) {
1641 activated_protocol_features.emplace( feature_digest, false );
1642 }
1643
1644 size_t num_preactivated_features_that_have_activated = 0;
1645
1646 const auto& pfs = protocol_features.get_protocol_feature_set();
1647 for( const auto& feature_digest : new_protocol_feature_activations ) {
1648 const auto& f = pfs.get_protocol_feature( feature_digest );
1649
1650 auto res = activated_protocol_features.emplace( feature_digest, true );
1651 if( res.second ) {
1652 // feature_digest was not preactivated
1653 SYS_ASSERT( !f.preactivation_required, protocol_feature_exception,
1654 "attempted to activate protocol feature without prior required preactivation: ${digest}",
1655 ("digest", feature_digest)
1656 );
1657 } else {
1658 SYS_ASSERT( !res.first->second, block_validate_exception,
1659 "attempted duplicate activation within a single block: ${digest}",
1660 ("digest", feature_digest)
1661 );
1662 // feature_digest was preactivated
1663 res.first->second = true;
1664 ++num_preactivated_features_that_have_activated;
1665 }
1666
1667 if( f.builtin_feature ) {
1668 trigger_activation_handler( *f.builtin_feature );
1669 }
1670
1671 protocol_features.activate_feature( feature_digest, pbhs.block_num );
1672
1673 ++bb._num_new_protocol_features_that_have_activated;
1674 }
1675
1676 if( num_preactivated_features_that_have_activated == num_preactivated_protocol_features ) {
1677 handled_all_preactivated_features = true;
1678 }
1679 }
1680
1681 SYS_ASSERT( handled_all_preactivated_features, block_validate_exception,
1682 "There are pre-activated protocol features that were not activated at the start of this block"
1683 );
1684
1685 if( new_protocol_feature_activations.size() > 0 ) {
1686 db.modify( pso, [&]( auto& ps ) {
1687 ps.preactivated_protocol_features.clear();
1688
1689 ps.activated_protocol_features.reserve( ps.activated_protocol_features.size()
1690 + new_protocol_feature_activations.size() );
1691 for( const auto& feature_digest : new_protocol_feature_activations ) {
1692 ps.activated_protocol_features.emplace_back( feature_digest, pbhs.block_num );
1693 }
1694 });
1695 }
1696
1697 const auto& gpo = db.get<global_property_object>();
1698
1699 if( gpo.proposed_schedule_block_num && // if there is a proposed schedule that was proposed in a block ...
1700 ( *gpo.proposed_schedule_block_num <= pbhs.dpos_irreversible_blocknum ) && // ... that has now become irreversible ...
1701 pbhs.prev_pending_schedule.schedule.producers.size() == 0 // ... and there was room for a new pending schedule prior to any possible promotion
1702 )
1703 {
1704 // Promote proposed schedule to pending schedule.
1705 if( !replaying ) {
1706 ilog( "promoting proposed schedule (set in block ${proposed_num}) to pending; current block: ${n} lib: ${lib} schedule: ${schedule} ",
1707 ("proposed_num", *gpo.proposed_schedule_block_num)("n", pbhs.block_num)
1708 ("lib", pbhs.dpos_irreversible_blocknum)
1709 ("schedule", producer_authority_schedule::from_shared(gpo.proposed_schedule) ) );
1710 }
1711
1712 SYS_ASSERT( gpo.proposed_schedule.version == pbhs.active_schedule_version + 1,
1713 producer_schedule_exception, "wrong producer schedule version specified" );
1714
1715 std::get<building_block>(pending->_block_stage)._new_pending_producer_schedule = producer_authority_schedule::from_shared(gpo.proposed_schedule);
1716 db.modify( gpo, [&]( auto& gp ) {
1717 gp.proposed_schedule_block_num = std::optional<block_num_type>();
1718 gp.proposed_schedule.version=0;
1719 gp.proposed_schedule.producers.clear();
1720 });
1721 }
1722
1723 try {
1725 transaction_metadata::create_no_recover_keys( std::make_shared<packed_transaction>( get_on_block_transaction() ),
1727 auto reset_in_trx_requiring_checks = fc::make_scoped_exit([old_value=in_trx_requiring_checks,this](){
1728 in_trx_requiring_checks = old_value;
1729 });
1733 if( trace->except ) {
1734 wlog("onblock ${block_num} is REJECTING: ${entire_trace}",("block_num", head->block_num + 1)("entire_trace", trace));
1735 }
1736 } catch( const std::bad_alloc& e ) {
1737 elog( "on block transaction failed due to a std::bad_alloc" );
1738 throw;
1739 } catch( const boost::interprocess::bad_alloc& e ) {
1740 elog( "on block transaction failed due to a bad allocation" );
1741 throw;
1742 } catch( const fc::exception& e ) {
1743 wlog( "on block transaction failed, but shouldn't impact block generation, system contract needs update" );
1744 edump((e.to_detail_string()));
1745 } catch( const std::exception& e ) {
1746 wlog( "on block transaction failed due to unexpected exception" );
1747 edump((e.what()));
1748 } catch( ... ) {
1749 elog( "on block transaction failed due to unknown exception" );
1750 }
1751
1754 }
1755
1756 guard_pending.cancel();
1757 }
signal< void(uint32_t)> block_start
void activate_feature(const digest_type &feature_digest, uint32_t current_block_num)
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 database_exception
uint32_t min_transaction_cpu_usage
the minimum billable cpu usage (in microseconds) that the chain requires
signed_transaction get_on_block_transaction()
void trigger_activation_handler(builtin_protocol_feature_t f)
static auto from_shared(const shared_producer_authority_schedule &src)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ startup() [1/3]

void sysio::chain::controller_impl::startup ( std::function< void()> shutdown,
std::function< bool()> check_shutdown )
inline

Definition at line 618 of file controller.cpp.

618 {
619 SYS_ASSERT( db.revision() >= 1, database_exception, "This version of controller::startup does not work with a fresh state database." );
620 SYS_ASSERT( fork_db.head(), fork_database_exception, "No existing fork database despite existing chain state. Replay required." );
621
622 this->shutdown = shutdown;
623 uint32_t lib_num = fork_db.root()->block_num;
624 auto first_block_num = blog.first_block_num();
625 if( blog.head() ) {
626 SYS_ASSERT( first_block_num <= lib_num && lib_num <= blog.head()->block_num(),
627 block_log_exception,
628 "block log (ranging from ${block_log_first_num} to ${block_log_last_num}) does not contain the last irreversible block (${fork_db_lib})",
629 ("block_log_first_num", first_block_num)
630 ("block_log_last_num", blog.head()->block_num())
631 ("fork_db_lib", lib_num)
632 );
633 lib_num = blog.head()->block_num();
634 } else {
635 if( first_block_num != (lib_num + 1) ) {
636 blog.reset( chain_id, lib_num + 1 );
637 }
638 }
639
640 if( read_mode == db_read_mode::IRREVERSIBLE && fork_db.head()->id != fork_db.root()->id ) {
642 }
643 head = fork_db.head();
644
645 init(check_shutdown);
646 }
void reset(const genesis_state &gs, const signed_block_ptr &genesis_block)
void init()
Definition lib_test.cpp:3
Here is the call graph for this function:

◆ startup() [2/3]

void sysio::chain::controller_impl::startup ( std::function< void()> shutdown,
std::function< bool()> check_shutdown,
const genesis_state & genesis )
inline

Definition at line 585 of file controller.cpp.

585 {
586 SYS_ASSERT( db.revision() < 1, database_exception, "This version of controller::startup only works with a fresh state database." );
587 const auto& genesis_chain_id = genesis.compute_chain_id();
588 SYS_ASSERT( genesis_chain_id == chain_id, chain_id_type_exception,
589 "genesis state provided to startup corresponds to a chain ID (${genesis_chain_id}) that does not match the chain ID that controller was constructed with (${controller_chain_id})",
590 ("genesis_chain_id", genesis_chain_id)("controller_chain_id", chain_id)
591 );
592
593 this->shutdown = shutdown;
594 if( fork_db.head() ) {
595 if( read_mode == db_read_mode::IRREVERSIBLE && fork_db.head()->id != fork_db.root()->id ) {
597 }
598 wlog( "No existing chain state. Initializing fresh blockchain state." );
599 } else {
600 wlog( "No existing chain state or fork database. Initializing fresh blockchain state and resetting fork database.");
601 }
602 initialize_blockchain_state(genesis); // sets head to genesis state
603
604 if( !fork_db.head() ) {
605 fork_db.reset( *head );
606 }
607
608 if( blog.head() ) {
609 SYS_ASSERT( blog.first_block_num() == 1, block_log_exception,
610 "block log does not start with genesis block"
611 );
612 } else {
613 blog.reset( genesis, head->block );
614 }
615 init(check_shutdown);
616 }
void initialize_blockchain_state(const genesis_state &genesis)
Here is the call graph for this function:

◆ startup() [3/3]

void sysio::chain::controller_impl::startup ( std::function< void()> shutdown,
std::function< bool()> check_shutdown,
const snapshot_reader_ptr & snapshot )
inline

Definition at line 557 of file controller.cpp.

557 {
558 SYS_ASSERT( snapshot, snapshot_exception, "No snapshot reader provided" );
559 this->shutdown = shutdown;
560 ilog( "Starting initialization from snapshot, this may take a significant amount of time" );
561 try {
562 snapshot->validate();
563 if( blog.head() ) {
564 read_from_snapshot( snapshot, blog.first_block_num(), blog.head()->block_num() );
565 } else {
566 read_from_snapshot( snapshot, 0, std::numeric_limits<uint32_t>::max() );
567 const uint32_t lib_num = head->block_num;
568 SYS_ASSERT( lib_num > 0, snapshot_exception,
569 "Snapshot indicates controller head at block number 0, but that is not allowed. "
570 "Snapshot is invalid." );
571 blog.reset( chain_id, lib_num + 1 );
572 }
573 const auto hash = calculate_integrity_hash();
574 ilog( "database initialized with hash: ${hash}", ("hash", hash) );
575
576 init(check_shutdown);
577 ilog( "Finished initialization from snapshot" );
578 } catch (boost::interprocess::bad_alloc& e) {
579 elog( "Failed initialization from snapshot - db storage not configured to have enough storage for the provided snapshot, please increase and retry snapshot" );
580 shutdown();
581 }
582
583 }
void read_from_snapshot(const snapshot_reader_ptr &snapshot, uint32_t blog_start, uint32_t blog_end)
Here is the call graph for this function:

◆ trigger_activation_handler()

void sysio::chain::controller_impl::trigger_activation_handler ( builtin_protocol_feature_t f)
inline

Definition at line 287 of file controller.cpp.

287 {
288 auto itr = protocol_feature_activation_handlers.find( f );
289 if( itr == protocol_feature_activation_handlers.end() ) return;
290 (itr->second)( *this );
291 }
Here is the caller graph for this function:

◆ update_producers_authority()

void sysio::chain::controller_impl::update_producers_authority ( )
inline

Definition at line 2334 of file controller.cpp.

2334 {
2335 const auto& producers = pending->get_pending_block_header_state().active_schedule.producers;
2336
2337 auto update_permission = [&]( auto& permission, auto threshold ) {
2338 auto auth = authority( threshold, {}, {});
2339 for( auto& p : producers ) {
2340 auth.accounts.push_back({{p.producer_name, config::active_name}, 1});
2341 }
2342
2343 if( static_cast<authority>(permission.auth) != auth ) { // TODO: use a more efficient way to check that authority has not changed
2344 db.modify(permission, [&]( auto& po ) {
2345 po.auth = auth;
2346 });
2347 }
2348 };
2349
2350 uint32_t num_producers = producers.size();
2351 auto calculate_threshold = [=]( uint32_t numerator, uint32_t denominator ) {
2352 return ( (num_producers * numerator) / denominator ) + 1;
2353 };
2354
2355 update_permission( authorization.get_permission({config::producers_account_name,
2356 config::active_name}),
2357 calculate_threshold( 2, 3 ) /* more than two-thirds */ );
2358
2359 update_permission( authorization.get_permission({config::producers_account_name,
2360 config::majority_producers_permission_name}),
2361 calculate_threshold( 1, 2 ) /* more than one-half */ );
2362
2363 update_permission( authorization.get_permission({config::producers_account_name,
2364 config::minority_producers_permission_name}),
2365 calculate_threshold( 1, 3 ) /* more than one-third */ );
2366
2367 //TODO: Add tests
2368 }
const mie::Vuint & p
Definition bn.cpp:27
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers producers(dont_start)) FC_REFLECT(testnet_def
Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_db_version()

static auto sysio::chain::controller_impl::validate_db_version ( const chainbase::database & db)
inlinestatic

Definition at line 649 of file controller.cpp.

649 {
650 // check database version
651 const auto& header_idx = db.get_index<database_header_multi_index>().indices().get<by_id>();
652
653 SYS_ASSERT(header_idx.begin() != header_idx.end(), bad_database_version_exception,
654 "state database version pre-dates versioning, please restore from a compatible snapshot or replay!");
655
656 auto header_itr = header_idx.begin();
657 header_itr->validate();
658
659 return header_itr;
660 }
chainbase::shared_multi_index_container< database_header_object, indexed_by< ordered_unique< tag< by_id >, BOOST_MULTI_INDEX_MEMBER(database_header_object, database_header_object::id_type, id)> > > database_header_multi_index
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ apply_handlers

map< account_name, map<handler_key, apply_handler> > sysio::chain::controller_impl::apply_handlers

Definition at line 256 of file controller.cpp.

◆ authorization

authorization_manager sysio::chain::controller_impl::authorization

Definition at line 238 of file controller.cpp.

◆ blog

block_log sysio::chain::controller_impl::blog

Definition at line 232 of file controller.cpp.

◆ chain_id

const chain_id_type sysio::chain::controller_impl::chain_id

Definition at line 241 of file controller.cpp.

◆ conf

controller::config sysio::chain::controller_impl::conf

Definition at line 240 of file controller.cpp.

◆ db

chainbase::database sysio::chain::controller_impl::db

Definition at line 231 of file controller.cpp.

◆ deep_mind_logger

deep_mind_handler* sysio::chain::controller_impl::deep_mind_logger = nullptr

Definition at line 250 of file controller.cpp.

◆ fork_db

fork_database sysio::chain::controller_impl::fork_db

Definition at line 235 of file controller.cpp.

◆ head

block_state_ptr sysio::chain::controller_impl::head

Definition at line 234 of file controller.cpp.

◆ in_trx_requiring_checks

bool sysio::chain::controller_impl::in_trx_requiring_checks = false

Definition at line 244 of file controller.cpp.

◆ pending

std::optional<pending_state> sysio::chain::controller_impl::pending

Definition at line 233 of file controller.cpp.

◆ protocol_feature_activation_handlers

unordered_map< builtin_protocol_feature_t, std::function<void(controller_impl&)>, enum_hash<builtin_protocol_feature_t> > sysio::chain::controller_impl::protocol_feature_activation_handlers

Definition at line 257 of file controller.cpp.

◆ protocol_features

protocol_feature_manager sysio::chain::controller_impl::protocol_features

Definition at line 239 of file controller.cpp.

◆ read_mode

db_read_mode sysio::chain::controller_impl::read_mode = db_read_mode::SPECULATIVE

Definition at line 243 of file controller.cpp.

◆ replaying

bool sysio::chain::controller_impl::replaying = false

Definition at line 242 of file controller.cpp.

◆ resource_limits

resource_limits_manager sysio::chain::controller_impl::resource_limits

Definition at line 237 of file controller.cpp.

◆ rnh

reset_new_handler sysio::chain::controller_impl::rnh

Definition at line 228 of file controller.cpp.

◆ self

controller& sysio::chain::controller_impl::self

Definition at line 229 of file controller.cpp.

◆ shutdown

std::function<void()> sysio::chain::controller_impl::shutdown

Definition at line 230 of file controller.cpp.

◆ snapshot_head_block

uint32_t sysio::chain::controller_impl::snapshot_head_block = 0

Definition at line 247 of file controller.cpp.

◆ subjective_cpu_leeway

std::optional<fc::microseconds> sysio::chain::controller_impl::subjective_cpu_leeway

Definition at line 245 of file controller.cpp.

◆ thread_pool

named_thread_pool sysio::chain::controller_impl::thread_pool

Definition at line 248 of file controller.cpp.

◆ timer

platform_timer sysio::chain::controller_impl::timer

Definition at line 249 of file controller.cpp.

◆ trusted_producer_light_validation

bool sysio::chain::controller_impl::trusted_producer_light_validation = false

Definition at line 246 of file controller.cpp.

◆ wasmif

wasm_interface sysio::chain::controller_impl::wasmif

Definition at line 236 of file controller.cpp.


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