Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
controller.cpp
Go to the documentation of this file.
3
7
20
28
30#include <sysio/vm/allocator.hpp>
31#include <fc/io/json.hpp>
33#include <fc/scoped_exit.hpp>
34#include <fc/variant_object.hpp>
35
36#include <new>
37
38namespace sysio { namespace chain {
39
40using resource_limits::resource_limits_manager;
41
55>;
56
64>;
65
67 public:
68 maybe_session() = default;
69
71 :_session(move(other._session))
72 {
73 }
74
75 explicit maybe_session(database& db) {
76 _session.emplace(db.start_undo_session(true));
77 }
78
79 maybe_session(const maybe_session&) = delete;
80
81 void squash() {
82 if (_session)
83 _session->squash();
84 }
85
86 void undo() {
87 if (_session)
88 _session->undo();
89 }
90
91 void push() {
92 if (_session)
93 _session->push();
94 }
95
97 if (mv._session) {
98 _session.emplace(move(*mv._session));
99 mv._session.reset();
100 } else {
101 _session.reset();
102 }
103
104 return *this;
105 };
106
107 private:
108 std::optional<database::session> _session;
109};
110
114 uint16_t num_prev_blocks_to_confirm,
115 const vector<digest_type>& new_protocol_feature_activations )
116 :_pending_block_header_state( prev.next( when, num_prev_blocks_to_confirm ) )
117 ,_new_protocol_feature_activations( new_protocol_feature_activations )
118 {}
119
121 std::optional<producer_authority_schedule> _new_pending_producer_schedule;
127 std::optional<checksum256_type> _transaction_mroot;
128 std::optional<s_header> _s_header; // Added new functionality to pass an optional s_header to be included in block header extension
129};
130
136
137 // if the _unsigned_block pre-dates block-signing authorities this may be present.
138 std::optional<producer_authority_schedule> _new_producer_authority_cache;
139};
140
144
145using block_stage_type = std::variant<building_block, assembled_block, completed_block>;
146
150 uint16_t num_prev_blocks_to_confirm,
151 const vector<digest_type>& new_protocol_feature_activations )
152 :_db_session( move(s) )
153 ,_block_stage( building_block( prev, when, num_prev_blocks_to_confirm, new_protocol_feature_activations ) )
154 {}
155
159 std::optional<block_id_type> _producer_block_id;
160
163 if( std::holds_alternative<building_block>(_block_stage) )
164 return std::get<building_block>(_block_stage)._pending_block_header_state;
165
166 return std::get<assembled_block>(_block_stage)._pending_block_header_state;
167 }
168
170 if( std::holds_alternative<building_block>(_block_stage) )
171 return std::get<building_block>(_block_stage)._pending_trx_receipts;
172
173 if( std::holds_alternative<assembled_block>(_block_stage) )
174 return std::get<assembled_block>(_block_stage)._unsigned_block->transactions;
175
176 return std::get<completed_block>(_block_stage)._block_state->block->transactions;
177 }
178
180 if( std::holds_alternative<building_block>(_block_stage) )
181 return std::move( std::get<building_block>(_block_stage)._pending_trx_metas );
182
183 if( std::holds_alternative<assembled_block>(_block_stage) )
184 return std::move( std::get<assembled_block>(_block_stage)._trx_metas );
185
186 return std::get<completed_block>(_block_stage)._block_state->extract_trxs_metas();
187 }
188
189 bool is_protocol_feature_activated( const digest_type& feature_digest )const {
190 if( std::holds_alternative<building_block>(_block_stage) ) {
191 auto& bb = std::get<building_block>(_block_stage);
192 const auto& activated_features = bb._pending_block_header_state.prev_activated_protocol_features->protocol_features;
193
194 if( activated_features.find( feature_digest ) != activated_features.end() ) return true;
195
196 if( bb._num_new_protocol_features_that_have_activated == 0 ) return false;
197
198 auto end = bb._new_protocol_feature_activations.begin() + bb._num_new_protocol_features_that_have_activated;
199 return (std::find( bb._new_protocol_feature_activations.begin(), end, feature_digest ) != end);
200 }
201
202 if( std::holds_alternative<assembled_block>(_block_stage) ) {
203 // Calling is_protocol_feature_activated during the assembled_block stage is not efficient.
204 // We should avoid doing it.
205 // In fact for now it isn't even implemented.
206 SYS_THROW( misc_exception,
207 "checking if protocol feature is activated in the assembled_block stage is not yet supported" );
208 // TODO: implement this
209 }
210
211 const auto& activated_features = std::get<completed_block>(_block_stage)._block_state->activated_protocol_features->protocol_features;
212 return (activated_features.find( feature_digest ) != activated_features.end());
213 }
214
215 void push() {
217 }
218};
219
221
222 // LLVM sets the new handler, we need to reset this to throw a bad_alloc exception so we can possibly exit cleanly
223 // and not just abort.
225 reset_new_handler() { std::set_new_handler([](){ throw std::bad_alloc(); }); }
226 };
227
228 reset_new_handler rnh; // placed here to allow for this to be set before constructing the other fields
230 std::function<void()> shutdown;
233 std::optional<pending_state> pending;
241 const chain_id_type chain_id; // read by thread_pool threads, value will not be changed
242 bool replaying = false;
245 std::optional<fc::microseconds> subjective_cpu_leeway;
251#if defined(SYSIO_SYS_VM_RUNTIME_ENABLED) || defined(SYSIO_SYS_VM_JIT_RUNTIME_ENABLED)
252 vm::wasm_allocator wasm_alloc;
253#endif
254
255 typedef pair<scope_name,action_name> handler_key;
256 map< account_name, map<handler_key, apply_handler> > apply_handlers;
258
259 void pop_block() {
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 }
277
278 template<builtin_protocol_feature_t F>
280
281 template<builtin_protocol_feature_t F>
284 SYS_ASSERT( res.second, misc_exception, "attempting to set activation handler twice" );
285 }
286
288 auto itr = protocol_feature_activation_handlers.find( f );
289 if( itr == protocol_feature_activation_handlers.end() ) return;
290 (itr->second)( *this );
291 }
292
294 apply_handlers[receiver][make_pair(contract,action)] = v;
295 }
296
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 }
357
367 template<typename Signal, typename Arg>
368 void emit( const Signal& s, Arg&& a ) {
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 }
388
390 if (auto dm_logger = get_deep_mind_logger()) {
391 dm_logger->on_applied_transaction(self.head_block_num() + 1, t);
392 }
393 }
394
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 }
448
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 }
474
475 void replay(std::function<bool()> check_shutdown) {
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 }
556
557 void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown, const snapshot_reader_ptr& snapshot) {
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 }
584
585 void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis) {
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 }
617
618 void startup(std::function<void()> shutdown, std::function<bool()> check_shutdown) {
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 }
647
648
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 }
661
662 void init(std::function<bool()> check_shutdown) {
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 }
723
726 pending.reset();
727 }
728
729 void add_indices() {
730 controller_index_set::add_indices(db);
731 contract_database_index_set::add_indices(db);
732
735 }
736
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 }
746
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 }
772
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 }
801
802 void add_to_snapshot( const snapshot_writer_ptr& snapshot ) {
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 }
839
840 static std::optional<genesis_state> extract_legacy_genesis_state( snapshot_reader& snapshot, uint32_t version ) {
841 std::optional<genesis_state> genesis;
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 }
852
853 void read_from_snapshot( const snapshot_reader_ptr& snapshot, uint32_t blog_start, uint32_t blog_end ) {
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;
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) {
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 }
977
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 }
986
987 void create_native_account( const fc::time_point& initial_timestamp, account_name name, const authority& owner, const authority& active, bool is_privileged = false ) {
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 }
1022
1023 void initialize_database(const genesis_state& genesis) {
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++)
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
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 }
1080
1081 // The returned scoped_exit should not exceed the lifetime of the pending which existed when make_block_restore_point was called.
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 }
1101
1103 fc::time_point block_deadline,
1104 fc::microseconds max_transaction_time,
1105 fc::time_point start,
1106 uint32_t& cpu_time_to_bill_us, // only set on failure
1107 uint32_t billed_cpu_time_us,
1108 bool explicit_billed_cpu_time = false,
1109 bool enforce_whiteblacklist = true
1110 )
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
1123 }
1124
1125 if (auto dm_logger = get_deep_mind_logger()) {
1126 dm_logger->on_onerror(etrx);
1127 }
1128
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 }
1179
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 }
1192
1193 bool failure_is_subjective( const fc::exception& e ) const {
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 }
1211
1213 auto code = e.code();
1214 return (code == tx_cpu_usage_exceeded::code_value)
1216 }
1217
1219 fc::time_point block_deadline, fc::microseconds max_transaction_time,
1220 uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
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 }
1227
1229 fc::time_point block_deadline, fc::microseconds max_transaction_time,
1230 uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time = false )
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
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 ) {
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;
1431
1432
1436 template<typename T>
1438 uint64_t cpu_usage_us, uint64_t net_usage ) {
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 }
1449
1456 fc::time_point block_deadline,
1457 fc::microseconds max_transaction_time,
1458 uint32_t billed_cpu_time_us,
1459 bool explicit_billed_cpu_time,
1460 int64_t subjective_cpu_bill_us )
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 ) {
1474 start = fc::time_point();
1475 } else {
1476 start -= already_consumed_time;
1477 }
1478 }
1479
1480 const signed_transaction& trn = trx->packed_trx()->get_signed_transaction();
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) {
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 {
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 }
1591
1593 uint16_t confirm_block_count,
1594 const vector<digest_type>& new_protocol_feature_activations,
1596 const std::optional<block_id_type>& producer_block_id,
1597 const fc::time_point& deadline )
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 }
1758
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 };
1823
1827 void commit_block( bool add_to_fork_db ) {
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 }
1865
1876 const flat_set<digest_type>& currently_activated_protocol_features,
1877 const vector<digest_type>& new_protocol_features )
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 }
1926
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 }
1946
1947
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 }
2077
2078
2079 // thread safe, expected to be called from thread other than the main thread
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 }
2101
2102 std::future<block_state_ptr> create_block_state_future( const block_id_type& id, const signed_block_ptr& b ) {
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 }
2117
2118 // thread safe, expected to be called from thread other than the main thread
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 }
2132
2133 void push_block( const block_state_ptr& bsp,
2134 const forked_branch_callback& forked_branch_cb,
2135 const trx_meta_cache_lookup& trx_lookup )
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 }
2171
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 }
2228
2230 const forked_branch_callback& forked_branch_cb, const trx_meta_cache_lookup& trx_lookup )
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 }
2314
2317 if( pending ) {
2318 applied_trxs = pending->extract_trx_metas();
2319 pending.reset();
2321 }
2322 return applied_trxs;
2323 }
2324
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 }
2333
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 }
2369
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 }
2377
2378
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 }
2396
2398 if( conf.sender_bypass_whiteblacklist.size() > 0 &&
2400 {
2401 return true;
2402 }
2403
2404 return false;
2405 }
2406
2407 void check_actor_list( const flat_set<account_name>& actors )const {
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 }
2491
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 }
2505
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 }
2515
2516 void check_key_list( const public_key_type& key )const {
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 }
2525
2526 /*
2527 bool should_check_tapos()const { return true; }
2528
2529 void validate_tapos( const transaction& trx )const {
2530 if( !should_check_tapos() ) return;
2531
2532 const auto& tapos_block_summary = db.get<block_summary_object>((uint16_t)trx.ref_block_num);
2533
2534 //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
2535 SYS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
2536 "Transaction's reference block did not match. Is this transaction from a different fork?",
2537 ("tapos_summary", tapos_block_summary));
2538 }
2539 */
2540
2541
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
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
2563 }
2564
2565 if (auto dm_logger = get_deep_mind_logger()) {
2566 dm_logger->on_onblock(trx);
2567 }
2568
2569 return trx;
2570 }
2571
2573 return deep_mind_logger;
2574 }
2575
2577 return (blog.first_block_num() != 0) ? blog.first_block_num() : fork_db.root()->block_num;
2578 }
2579
2580};
2581
2583{
2584 return my->resource_limits;
2585}
2587{
2588 return my->resource_limits;
2589}
2590
2592{
2593 return my->authorization;
2594}
2596{
2597 return my->authorization;
2598}
2599
2601{
2602 return my->protocol_features;
2603}
2604
2606{
2607 return my->conf.max_nonprivileged_inline_action_size;
2608}
2609
2611:my( new controller_impl( cfg, *this, protocol_feature_set{}, chain_id ) )
2612{
2613}
2614
2616:my( new controller_impl( cfg, *this, std::move(pfs), chain_id ) )
2617{
2618}
2619
2621 my->abort_block();
2622 /* Shouldn't be needed anymore.
2623 //close fork_db here, because it can generate "irreversible" signal to this controller,
2624 //in case if read-mode == IRREVERSIBLE, we will apply latest irreversible block
2625 //for that we need 'my' to be valid pointer pointing to valid controller_impl.
2626 my->fork_db.close();
2627 */
2628}
2629
2631 my->add_indices();
2632}
2633
2634void controller::startup( std::function<void()> shutdown, std::function<bool()> check_shutdown, const snapshot_reader_ptr& snapshot ) {
2635 my->startup(shutdown, check_shutdown, snapshot);
2636}
2637
2638void controller::startup( std::function<void()> shutdown, std::function<bool()> check_shutdown, const genesis_state& genesis ) {
2639 my->startup(shutdown, check_shutdown, genesis);
2640}
2641
2642void controller::startup(std::function<void()> shutdown, std::function<bool()> check_shutdown) {
2643 my->startup(shutdown, check_shutdown);
2644}
2645
2646const chainbase::database& controller::db()const { return my->db; }
2647
2648chainbase::database& controller::mutable_db()const { return my->db; }
2649
2650const fork_database& controller::fork_db()const { return my->fork_db; }
2651
2652void controller::preactivate_feature( const digest_type& feature_digest ) {
2653 const auto& pfs = my->protocol_features.get_protocol_feature_set();
2654 auto cur_time = pending_block_time();
2655
2656 auto status = pfs.is_recognized( feature_digest, cur_time );
2657 switch( status ) {
2659 if( is_producing_block() ) {
2660 SYS_THROW( subjective_block_production_exception,
2661 "protocol feature with digest '${digest}' is unrecognized", ("digest", feature_digest) );
2662 } else {
2663 SYS_THROW( protocol_feature_bad_block_exception,
2664 "protocol feature with digest '${digest}' is unrecognized", ("digest", feature_digest) );
2665 }
2666 break;
2668 if( is_producing_block() ) {
2669 SYS_THROW( subjective_block_production_exception,
2670 "protocol feature with digest '${digest}' is disabled", ("digest", feature_digest) );
2671 } else {
2672 SYS_THROW( protocol_feature_bad_block_exception,
2673 "protocol feature with digest '${digest}' is disabled", ("digest", feature_digest) );
2674 }
2675 break;
2677 if( is_producing_block() ) {
2678 SYS_THROW( subjective_block_production_exception,
2679 "${timestamp} is too early for the earliest allowed activation time of the protocol feature with digest '${digest}'", ("digest", feature_digest)("timestamp", cur_time) );
2680 } else {
2681 SYS_THROW( protocol_feature_bad_block_exception,
2682 "${timestamp} is too early for the earliest allowed activation time of the protocol feature with digest '${digest}'", ("digest", feature_digest)("timestamp", cur_time) );
2683 }
2684 break;
2686 break;
2687 default:
2688 if( is_producing_block() ) {
2689 SYS_THROW( subjective_block_production_exception, "unexpected recognized_t status" );
2690 } else {
2691 SYS_THROW( protocol_feature_bad_block_exception, "unexpected recognized_t status" );
2692 }
2693 break;
2694 }
2695
2696 // The above failures depend on subjective information.
2697 // Because of deferred transactions, this complicates things considerably.
2698
2699 // If producing a block, we throw a subjective failure if the feature is not properly recognized in order
2700 // to try to avoid retiring into a block a deferred transacton driven by subjective information.
2701
2702 // But it is still possible for a producer to retire a deferred transaction that deals with this subjective
2703 // information. If they recognized the feature, they would retire it successfully, but a validator that
2704 // does not recognize the feature should reject the entire block (not just fail the deferred transaction).
2705 // Even if they don't recognize the feature, the producer could change their nodeop code to treat it like an
2706 // objective failure thus leading the deferred transaction to retire with soft_fail or hard_fail.
2707 // In this case, validators that don't recognize the feature would reject the whole block immediately, and
2708 // validators that do recognize the feature would likely lead to a different retire status which would
2709 // ultimately cause a validation failure and thus rejection of the block.
2710 // In either case, it results in rejection of the block which is the desired behavior in this scenario.
2711
2712 // If the feature is properly recognized by producer and validator, we have dealt with the subjectivity and
2713 // now only consider the remaining failure modes which are deterministic and objective.
2714 // Thus the exceptions that can be thrown below can be regular objective exceptions
2715 // that do not cause immediate rejection of the block.
2716
2717 SYS_ASSERT( !is_protocol_feature_activated( feature_digest ),
2718 protocol_feature_exception,
2719 "protocol feature with digest '${digest}' is already activated",
2720 ("digest", feature_digest)
2721 );
2722
2723 const auto& pso = my->db.get<protocol_state_object>();
2724
2725 SYS_ASSERT( std::find( pso.preactivated_protocol_features.begin(),
2726 pso.preactivated_protocol_features.end(),
2727 feature_digest
2728 ) == pso.preactivated_protocol_features.end(),
2729 protocol_feature_exception,
2730 "protocol feature with digest '${digest}' is already pre-activated",
2731 ("digest", feature_digest)
2732 );
2733
2734 auto dependency_checker = [&]( const digest_type& d ) -> bool
2735 {
2736 if( is_protocol_feature_activated( d ) ) return true;
2737
2738 return ( std::find( pso.preactivated_protocol_features.begin(),
2739 pso.preactivated_protocol_features.end(),
2740 d ) != pso.preactivated_protocol_features.end() );
2741 };
2742
2743 SYS_ASSERT( pfs.validate_dependencies( feature_digest, dependency_checker ),
2744 protocol_feature_exception,
2745 "not all dependencies of protocol feature with digest '${digest}' have been activated or pre-activated",
2746 ("digest", feature_digest)
2747 );
2748
2749 if (auto dm_logger = get_deep_mind_logger()) {
2750 const auto feature = pfs.get_protocol_feature(feature_digest);
2751
2752 dm_logger->on_preactivate_feature(feature);
2753 }
2754
2755 my->db.modify( pso, [&]( auto& ps ) {
2756 ps.preactivated_protocol_features.push_back( feature_digest );
2757 } );
2758}
2759
2761 const auto& pso = my->db.get<protocol_state_object>();
2762
2763 if( pso.preactivated_protocol_features.size() == 0 ) return {};
2764
2765 vector<digest_type> preactivated_protocol_features;
2766
2767 for( const auto& f : pso.preactivated_protocol_features ) {
2768 preactivated_protocol_features.emplace_back( f );
2769 }
2770
2771 return preactivated_protocol_features;
2772}
2773
2774void controller::validate_protocol_features( const vector<digest_type>& features_to_activate )const {
2775 my->check_protocol_features( my->head->header.timestamp,
2776 my->head->activated_protocol_features->protocol_features,
2777 features_to_activate );
2778}
2779
2781{
2783
2784 SYS_ASSERT( !my->pending, block_validate_exception, "pending block already exists" );
2785
2786 vector<digest_type> new_protocol_feature_activations;
2787
2788 const auto& pso = my->db.get<protocol_state_object>();
2789 if( pso.preactivated_protocol_features.size() > 0 ) {
2790 for( const auto& f : pso.preactivated_protocol_features ) {
2791 new_protocol_feature_activations.emplace_back( f );
2792 }
2793 }
2794
2795 if( new_protocol_feature_activations.size() > 0 ) {
2796 validate_protocol_features( new_protocol_feature_activations );
2797 }
2798
2799 my->start_block( when, confirm_block_count, new_protocol_feature_activations,
2800 block_status::incomplete, std::optional<block_id_type>(), fc::time_point::maximum() );
2801}
2802
2804 uint16_t confirm_block_count,
2805 const vector<digest_type>& new_protocol_feature_activations,
2806 const fc::time_point& deadline )
2807{
2809
2810 if( new_protocol_feature_activations.size() > 0 ) {
2811 validate_protocol_features( new_protocol_feature_activations );
2812 }
2813
2814 my->start_block( when, confirm_block_count, new_protocol_feature_activations,
2815 block_status::incomplete, std::optional<block_id_type>(), deadline );
2816}
2817
2820
2821 my->finalize_block();
2822
2823 auto& ab = std::get<assembled_block>(my->pending->_block_stage);
2824
2825 auto bsp = std::make_shared<block_state>(
2826 std::move( ab._pending_block_header_state ),
2827 std::move( ab._unsigned_block ),
2828 std::move( ab._trx_metas ),
2829 my->protocol_features.get_protocol_feature_set(),
2830 []( block_timestamp_type timestamp,
2831 const flat_set<digest_type>& cur_features,
2832 const vector<digest_type>& new_features )
2833 {},
2834 signer_callback
2835 );
2836
2837 my->pending->_block_stage = completed_block{ bsp };
2838
2839 return bsp;
2840}
2841
2844 my->commit_block(true);
2845}
2846
2848 return my->abort_block();
2849}
2850
2851boost::asio::io_context& controller::get_thread_pool() {
2852 return my->thread_pool.get_executor();
2853}
2854
2855std::future<block_state_ptr> controller::create_block_state_future( const block_id_type& id, const signed_block_ptr& b ) {
2856 return my->create_block_state_future( id, b );
2857}
2858
2860 return my->create_block_state( id, b );
2861}
2862
2864 const forked_branch_callback& forked_branch_cb,
2865 const trx_meta_cache_lookup& trx_lookup )
2866{
2868 my->push_block( bsp, forked_branch_cb, trx_lookup );
2869}
2870
2872 fc::time_point block_deadline, fc::microseconds max_transaction_time,
2873 uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time,
2874 int64_t subjective_cpu_bill_us ) {
2876 SYS_ASSERT( get_read_mode() != db_read_mode::IRREVERSIBLE, transaction_type_exception, "push transaction not allowed in irreversible mode" );
2877 SYS_ASSERT( trx && !trx->implicit && !trx->scheduled, transaction_type_exception, "Implicit/Scheduled transaction not allowed" );
2878 return my->push_transaction(trx, block_deadline, max_transaction_time, billed_cpu_time_us, explicit_billed_cpu_time, subjective_cpu_bill_us );
2879}
2880
2882 fc::time_point block_deadline, fc::microseconds max_transaction_time,
2883 uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time )
2884{
2885 SYS_ASSERT( get_read_mode() != db_read_mode::IRREVERSIBLE, transaction_type_exception, "push scheduled transaction not allowed in irreversible mode" );
2887 return my->push_scheduled_transaction( trxid, block_deadline, max_transaction_time, billed_cpu_time_us, explicit_billed_cpu_time );
2888}
2889
2890const flat_set<account_name>& controller::get_actor_whitelist() const {
2891 return my->conf.actor_whitelist;
2892}
2893const flat_set<account_name>& controller::get_actor_blacklist() const {
2894 return my->conf.actor_blacklist;
2895}
2896const flat_set<account_name>& controller::get_contract_whitelist() const {
2897 return my->conf.contract_whitelist;
2898}
2899const flat_set<account_name>& controller::get_contract_blacklist() const {
2900 return my->conf.contract_blacklist;
2901}
2902const flat_set< pair<account_name, action_name> >& controller::get_action_blacklist() const {
2903 return my->conf.action_blacklist;
2904}
2905const flat_set<public_key_type>& controller::get_key_blacklist() const {
2906 return my->conf.key_blacklist;
2907}
2908
2909void controller::set_actor_whitelist( const flat_set<account_name>& new_actor_whitelist ) {
2910 my->conf.actor_whitelist = new_actor_whitelist;
2911}
2912void controller::set_actor_blacklist( const flat_set<account_name>& new_actor_blacklist ) {
2913 my->conf.actor_blacklist = new_actor_blacklist;
2914}
2915void controller::set_contract_whitelist( const flat_set<account_name>& new_contract_whitelist ) {
2916 my->conf.contract_whitelist = new_contract_whitelist;
2917}
2918void controller::set_contract_blacklist( const flat_set<account_name>& new_contract_blacklist ) {
2919 my->conf.contract_blacklist = new_contract_blacklist;
2920}
2921void controller::set_action_blacklist( const flat_set< pair<account_name, action_name> >& new_action_blacklist ) {
2922 for (auto& act: new_action_blacklist) {
2923 SYS_ASSERT(act.first != account_name(), name_type_exception, "Action blacklist - contract name should not be empty");
2924 SYS_ASSERT(act.second != action_name(), action_type_exception, "Action blacklist - action name should not be empty");
2925 }
2926 my->conf.action_blacklist = new_action_blacklist;
2927}
2928void controller::set_key_blacklist( const flat_set<public_key_type>& new_key_blacklist ) {
2929 my->conf.key_blacklist = new_key_blacklist;
2930}
2932 // ilog("CONTROLLER - setting s header: ${s}", ("s", s_header.to_string()));
2933 SYS_ASSERT( my->pending, block_validate_exception, "it is not valid to set_s_header when there is no pending block");
2934 SYS_ASSERT( std::holds_alternative<building_block>(my->pending->_block_stage), block_validate_exception, "already called finalize_block");
2935 // SYS_ASSERT( std::get<assembled_block>(pending->_block_stage)._id == id, block_validate_exception, "mismatching block id" );
2936 // Try to set it first in the pending block
2937 auto& bb = std::get<building_block>(my->pending->_block_stage);
2938 bb._s_header = s_header; // Attempt to set s-header
2939 auto& check_s_header = std::get<building_block>(my->pending->_block_stage)._s_header;
2940 if (check_s_header){
2941 ilog("Pending building block s_header set: ${s_header}\n\t\tand matches what was passed: ${match}",
2942 ("s_header", check_s_header->to_string())("match", check_s_header == s_header));
2943 }
2944 else {
2945 ilog("Pending building block s_header NOT SET");
2946 }
2947}
2948
2950 return my->head->block_num;
2951}
2953 return my->head->header.timestamp;
2954}
2956 return my->head->id;
2957}
2959 return my->head->header.producer;
2960}
2962 return my->head->header;
2963}
2965 return my->head;
2966}
2967
2969 return my->fork_db.head()->block_num;
2970}
2971
2973 return my->fork_db.head()->id;
2974}
2975
2977 return my->fork_db.head()->header.timestamp;
2978}
2979
2981 return my->fork_db.head()->header.producer;
2982}
2983
2985 return my->fork_db.pending_head()->block_num;
2986}
2987
2989 return my->fork_db.pending_head()->id;
2990}
2991
2993 return my->fork_db.pending_head()->header.timestamp;
2994}
2995
2997 return my->fork_db.pending_head()->header.producer;
2998}
2999
3001 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3002
3003 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3004 return std::get<completed_block>(my->pending->_block_stage)._block_state->header.timestamp;
3005
3006 return my->pending->get_pending_block_header_state().timestamp;
3007}
3008
3010 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3011
3012 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3013 return std::get<completed_block>(my->pending->_block_stage)._block_state->header.block_num();
3014
3015 return my->pending->get_pending_block_header_state().block_num;
3016}
3017
3019 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3020
3021 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3022 return std::get<completed_block>(my->pending->_block_stage)._block_state->header.producer;
3023
3024 return my->pending->get_pending_block_header_state().producer;
3025}
3026
3028 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3029
3030 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3031 return std::get<completed_block>(my->pending->_block_stage)._block_state->valid_block_signing_authority;
3032
3033 return my->pending->get_pending_block_header_state().valid_block_signing_authority;
3034}
3035
3036std::optional<block_id_type> controller::pending_producer_block_id()const {
3037 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3038 return my->pending->_producer_block_id;
3039}
3040
3042 SYS_ASSERT( my->pending, block_validate_exception, "no pending block" );
3043 return my->pending->get_trx_receipts();
3044}
3045
3047 return my->fork_db.root()->block_num;
3048}
3049
3051 return my->fork_db.root()->id;
3052}
3053
3055 return my->fork_db.root()->header.timestamp.to_time_point();
3056}
3057
3058
3065
3067 auto state = my->fork_db.get_block(id);
3068 if( state && state->block ) return state->block;
3069 auto bptr = my->blog.read_block_by_num( block_header::num_from_id(id) );
3070 if( bptr && bptr->calculate_id() == id ) return bptr;
3071 return signed_block_ptr();
3072}
3073
3075 auto blk_state = fetch_block_state_by_number( block_num );
3076 if( blk_state ) {
3077 return blk_state->block;
3078 }
3079
3080 return my->blog.read_block_by_num(block_num);
3081} FC_CAPTURE_AND_RETHROW( (block_num) ) }
3082
3084 auto state = my->fork_db.get_block(id);
3085 return state;
3086}
3087
3089 if( my->read_mode == db_read_mode::IRREVERSIBLE ) {
3090 return my->fork_db.search_on_branch( my->fork_db.pending_head()->id, block_num );
3091 } else {
3092 return my->fork_db.search_on_branch( my->fork_db.head()->id, block_num );
3093 }
3094} FC_CAPTURE_AND_RETHROW( (block_num) ) }
3095
3097 const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)block_num);
3098
3099 if( block_header::num_from_id(tapos_block_summary.block_id) == block_num )
3100 return tapos_block_summary.block_id;
3101
3102 const auto& blog_head = my->blog.head();
3103
3104 bool find_in_blog = (blog_head && block_num <= blog_head->block_num());
3105
3106 if( !find_in_blog ) {
3107 auto bsp = fetch_block_state_by_number( block_num );
3108 if( bsp ) return bsp->id;
3109 }
3110
3111 auto id = my->blog.read_block_id_by_num(block_num);
3112
3113 SYS_ASSERT( BOOST_LIKELY( id != block_id_type() ), unknown_block_exception,
3114 "Could not find block: ${block}", ("block", block_num) );
3115
3116 return id;
3117} FC_CAPTURE_AND_RETHROW( (block_num) ) }
3118
3120 return my->calculate_integrity_hash();
3122
3124 SYS_ASSERT( !my->pending, block_validate_exception, "cannot take a consistent snapshot with a pending block" );
3125 return my->add_to_snapshot(snapshot);
3126}
3127
3129 const auto& gpo = get_global_properties();
3130 auto cur_block_num = head_block_num() + 1;
3131
3133 return -1;
3134 }
3135
3136 if( gpo.proposed_schedule_block_num ) {
3137 if( *gpo.proposed_schedule_block_num != cur_block_num )
3138 return -1; // there is already a proposed schedule set in a previous block, wait for it to become pending
3139
3140 if( std::equal( producers.begin(), producers.end(),
3141 gpo.proposed_schedule.producers.begin(), gpo.proposed_schedule.producers.end() ) )
3142 return -1; // the proposed producer schedule does not change
3143 }
3144
3146
3147 decltype(sch.producers.cend()) end;
3148 decltype(end) begin;
3149
3150 const auto& pending_sch = pending_producers();
3151
3152 if( pending_sch.producers.size() == 0 ) {
3153 const auto& active_sch = active_producers();
3154 begin = active_sch.producers.begin();
3155 end = active_sch.producers.end();
3156 sch.version = active_sch.version + 1;
3157 } else {
3158 begin = pending_sch.producers.begin();
3159 end = pending_sch.producers.end();
3160 sch.version = pending_sch.version + 1;
3161 }
3162
3163 if( std::equal( producers.begin(), producers.end(), begin, end ) )
3164 return -1; // the producer schedule would not change
3165
3166 sch.producers = std::move(producers);
3167
3168 int64_t version = sch.version;
3169
3170 ilog( "proposed producer schedule with version ${v}", ("v", version) );
3171
3172 my->db.modify( gpo, [&]( auto& gp ) {
3173 gp.proposed_schedule_block_num = cur_block_num;
3174 gp.proposed_schedule = sch.to_shared(gp.proposed_schedule.producers.get_allocator());
3175 });
3176 return version;
3177}
3178
3180 if( !(my->pending) )
3181 return my->head->active_schedule;
3182
3183 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3184 return std::get<completed_block>(my->pending->_block_stage)._block_state->active_schedule;
3185
3186 return my->pending->get_pending_block_header_state().active_schedule;
3187}
3188
3190 if( !(my->pending) )
3191 return my->head->pending_schedule.schedule;
3192
3193 if( std::holds_alternative<completed_block>(my->pending->_block_stage) )
3194 return std::get<completed_block>(my->pending->_block_stage)._block_state->pending_schedule.schedule;
3195
3196 if( std::holds_alternative<assembled_block>(my->pending->_block_stage) ) {
3197 const auto& new_prods_cache = std::get<assembled_block>(my->pending->_block_stage)._new_producer_authority_cache;
3198 if( new_prods_cache ) {
3199 return *new_prods_cache;
3200 }
3201 }
3202
3203 const auto& bb = std::get<building_block>(my->pending->_block_stage);
3204
3205 if( bb._new_pending_producer_schedule )
3206 return *bb._new_pending_producer_schedule;
3207
3208 return bb._pending_block_header_state.prev_pending_schedule.schedule;
3209}
3210
3211std::optional<producer_authority_schedule> controller::proposed_producers()const {
3212 const auto& gpo = get_global_properties();
3213 if( !gpo.proposed_schedule_block_num )
3214 return std::optional<producer_authority_schedule>();
3215
3216 return producer_authority_schedule::from_shared(gpo.proposed_schedule);
3217}
3218
3220 if (!my->pending || my->in_trx_requiring_checks) {
3221 return false;
3222 }
3223
3224 const auto pb_status = my->pending->_block_status;
3225
3226 // in a pending irreversible or previously validated block and we have forcing all checks
3227 const bool consider_skipping_on_replay =
3228 (pb_status == block_status::irreversible || pb_status == block_status::validated) && !my->conf.force_all_checks;
3229
3230 // OR in a signed block and in light validation mode
3231 const bool consider_skipping_on_validate = (pb_status == block_status::complete &&
3232 (my->conf.block_validation_mode == validation_mode::LIGHT || my->trusted_producer_light_validation));
3233
3234 return consider_skipping_on_replay || consider_skipping_on_validate;
3235}
3236
3237
3239 return light_validation_allowed();
3240}
3241
3243 return light_validation_allowed();
3244}
3245
3247 bool consider_skipping = bs == block_status::irreversible;
3248 return consider_skipping
3249 && !my->conf.disable_replay_opts
3250 && !my->in_trx_requiring_checks;
3251}
3252
3254 if (my->pending) {
3255 return skip_db_sessions(my->pending->_block_status);
3256 } else {
3257 return false;
3258 }
3259}
3260
3261bool controller::is_trusted_producer( const account_name& producer) const {
3262 return get_validation_mode() == chain::validation_mode::LIGHT || my->conf.trusted_producers.count(producer);
3263}
3264
3266 return my->conf.contracts_console;
3267}
3268
3270 return my->conf.profile_accounts.find(account) != my->conf.profile_accounts.end();
3271}
3272
3274 return my->chain_id;
3275}
3276
3278 return my->read_mode;
3279}
3280
3282 return my->conf.block_validation_mode;
3283}
3284
3286 return my->conf.terminate_at_block;
3287}
3288
3290{
3291 auto native_handler_scope = my->apply_handlers.find( receiver );
3292 if( native_handler_scope != my->apply_handlers.end() ) {
3293 auto handler = native_handler_scope->second.find( make_pair( scope, act ) );
3294 if( handler != native_handler_scope->second.end() )
3295 return &handler->second;
3296 }
3297 return nullptr;
3298}
3300 return my->wasmif;
3301}
3302
3304{ try {
3305 return my->db.get<account_object, by_name>(name);
3307
3309 return my->sender_avoids_whitelist_blacklist_enforcement( sender );
3310}
3311
3312void controller::check_actor_list( const flat_set<account_name>& actors )const {
3313 my->check_actor_list( actors );
3314}
3315
3317 my->check_contract_list( code );
3318}
3319
3321 my->check_action_list( code, action );
3322}
3323
3325 my->check_key_list( key );
3326}
3327
3329 return my->pending.has_value();
3330}
3331
3333 if( !my->pending ) return false;
3334
3335 return (my->pending->_block_status == block_status::incomplete);
3336}
3337
3339 return my->conf.disable_all_subjective_mitigations || !is_producing_block() || my->conf.allow_ram_billing_in_notify;
3340}
3341
3343 return my->conf.maximum_variable_signature_length;
3344}
3345
3346void controller::validate_expiration( const transaction& trx )const { try {
3347 const auto& chain_configuration = get_global_properties().configuration;
3348
3350 expired_tx_exception,
3351 "transaction has expired, "
3352 "expiration is ${trx.expiration} and pending block time is ${pending_block_time}",
3353 ("trx.expiration",trx.expiration)("pending_block_time",pending_block_time()));
3354 SYS_ASSERT( time_point(trx.expiration) <= pending_block_time() + fc::seconds(chain_configuration.max_transaction_lifetime),
3355 tx_exp_too_far_exception,
3356 "Transaction expiration is too far in the future relative to the reference time of ${reference_time}, "
3357 "expiration is ${trx.expiration} and the maximum transaction lifetime is ${max_til_exp} seconds",
3358 ("trx.expiration",trx.expiration)("reference_time",pending_block_time())
3359 ("max_til_exp",chain_configuration.max_transaction_lifetime) );
3360} FC_CAPTURE_AND_RETHROW((trx)) }
3361
3362void controller::validate_tapos( const transaction& trx )const { try {
3363 const auto& tapos_block_summary = db().get<block_summary_object>((uint16_t)trx.ref_block_num);
3364
3365 //Verify TaPoS block summary has correct ID prefix, and that this block's time is not past the expiration
3366 SYS_ASSERT(trx.verify_reference_block(tapos_block_summary.block_id), invalid_ref_block_exception,
3367 "Transaction's reference block did not match. Is this transaction from a different fork?",
3368 ("tapos_summary", tapos_block_summary));
3370
3372 const auto free = db().get_segment_manager()->get_free_memory();
3373 const auto guard = my->conf.state_guard_size;
3374 SYS_ASSERT(free >= guard, database_guard_exception, "database free: ${f}, guard size: ${g}", ("f", free)("g",guard));
3375}
3376
3377bool controller::is_protocol_feature_activated( const digest_type& feature_digest )const {
3378 if( my->pending )
3379 return my->pending->is_protocol_feature_activated( feature_digest );
3380
3381 const auto& activated_features = my->head->activated_protocol_features->protocol_features;
3382 return (activated_features.find( feature_digest ) != activated_features.end());
3383}
3384
3386 uint32_t current_block_num = head_block_num();
3387
3388 if( my->pending ) {
3389 ++current_block_num;
3390 }
3391
3392 return my->protocol_features.is_builtin_activated( f, current_block_num );
3393}
3394
3396 return db().find<transaction_object, by_trx_id>(id);
3397}
3398
3400 my->subjective_cpu_leeway = leeway;
3401}
3402
3403std::optional<fc::microseconds> controller::get_subjective_cpu_leeway() const {
3404 return my->subjective_cpu_leeway;
3405}
3406
3408 SYS_ASSERT( 0 < limit && limit <= chain::config::maximum_elastic_resource_multiplier,
3409 misc_exception,
3410 "Invalid limit (${limit}) passed into set_greylist_limit. "
3411 "Must be between 1 and ${max}.",
3412 ("limit", limit)("max", chain::config::maximum_elastic_resource_multiplier)
3413 );
3414 my->conf.greylist_limit = limit;
3415}
3416
3418 return my->conf.greylist_limit;
3419}
3420
3422 my->conf.resource_greylist.insert(name);
3423}
3424
3426 my->conf.resource_greylist.erase(name);
3427}
3428
3430 return my->conf.resource_greylist.find(name) != my->conf.resource_greylist.end();
3431}
3432
3433const flat_set<account_name> &controller::get_resource_greylist() const {
3434 return my->conf.resource_greylist;
3435}
3436
3437
3439 auto ptr = my->db.find<account_ram_correction_object, by_name>( account );
3440 if( ptr ) {
3441 my->db.modify<account_ram_correction_object>( *ptr, [&]( auto& rco ) {
3442 rco.ram_correction += ram_bytes;
3443 } );
3444 } else {
3445 ptr = &my->db.create<account_ram_correction_object>( [&]( auto& rco ) {
3446 rco.name = account;
3447 rco.ram_correction = ram_bytes;
3448 } );
3449 }
3450
3451 if (auto dm_logger = get_deep_mind_logger()) {
3452 dm_logger->on_add_ram_correction(*ptr, ram_bytes);
3453 }
3454}
3455
3457 return my->conf.disable_all_subjective_mitigations;
3458}
3459
3461 return my->get_deep_mind_logger();
3462}
3463
3465 SYS_ASSERT( logger != nullptr, misc_exception, "Invalid logger passed into enable_deep_mind, must be set" );
3466 my->deep_mind_logger = logger;
3467}
3468
3470 return my->earliest_available_block_num();
3471}
3472#if defined(SYSIO_SYS_VM_RUNTIME_ENABLED) || defined(SYSIO_SYS_VM_JIT_RUNTIME_ENABLED)
3473vm::wasm_allocator& controller::get_wasm_allocator() {
3474 return my->wasm_alloc;
3475}
3476#endif
3477
3479 const chain_exception* e_ptr = dynamic_cast<const chain_exception*>( &e );
3480
3481 if( e_ptr == nullptr ) return {};
3482
3483 if( !e_ptr->error_code ) return static_cast<uint64_t>(system_error_code::generic_system_error);
3484
3485 return e_ptr->error_code;
3486}
3487
3489 chain_snapshot_header header;
3490 snapshot.read_section<chain_snapshot_header>([&header]( auto &section ){
3491 section.read_row(header);
3492 header.validate();
3493 });
3494
3495 // check if this is a legacy version of the snapshot, which has a genesis state instead of chain id
3496 std::optional<genesis_state> genesis = controller_impl::extract_legacy_genesis_state(snapshot, header.version);
3497 if (genesis) {
3498 return genesis->compute_chain_id();
3499 }
3500
3501 chain_id_type chain_id;
3502
3504 if (header.version <= v4::maximum_version) {
3505 snapshot.read_section<global_property_object>([&chain_id]( auto &section ){
3506 v4 global_properties;
3507 section.read_row(global_properties);
3508 chain_id = global_properties.chain_id;
3509 });
3510 }
3511 else {
3512 snapshot.read_section<global_property_object>([&chain_id]( auto &section ){
3513 snapshot_global_property_object global_properties;
3514 section.read_row(global_properties);
3515 chain_id = global_properties.chain_id;
3516 });
3517 }
3518
3519 return chain_id;
3520}
3521
3522std::optional<chain_id_type> controller::extract_chain_id_from_db( const path& state_dir ) {
3523 try {
3525
3528
3530
3531 if( db.revision() < 1 ) return {};
3532
3533 return db.get<global_property_object>().chain_id;
3534 } catch( const bad_database_version_exception& ) {
3535 throw;
3536 } catch( ... ) {
3537 }
3538
3539 return {};
3540}
3541
3543 ilog("Replace producer keys with ${k}", ("k", key));
3544 mutable_db().modify( db().get<global_property_object>(), [&]( auto& gp ) {
3545 gp.proposed_schedule_block_num = {};
3546 gp.proposed_schedule.version = 0;
3547 gp.proposed_schedule.producers.clear();
3548 });
3549 auto version = my->head->pending_schedule.schedule.version;
3550 my->head->pending_schedule = {};
3551 my->head->pending_schedule.schedule.version = version;
3552 for (auto& prod: my->head->active_schedule.producers ) {
3553 ilog("${n}", ("n", prod.producer_name));
3554 std::visit([&](auto &auth) {
3555 auth.threshold = 1;
3556 auth.keys = {key_weight{key, 1}};
3557 }, prod.authority);
3558 }
3559}
3560
3561void controller::replace_account_keys( name account, name permission, const public_key_type& key ) {
3563 auto* perm = db().find<permission_object, by_owner>(boost::make_tuple(account, permission));
3564 if (!perm)
3565 return;
3566 int64_t old_size = (int64_t)(chain::config::billable_size_v<permission_object> + perm->auth.get_billable_size());
3567 mutable_db().modify(*perm, [&](auto& p) {
3568 p.auth = authority(key);
3569 });
3570 int64_t new_size = (int64_t)(chain::config::billable_size_v<permission_object> + perm->auth.get_billable_size());
3571 rlm.add_pending_ram_usage(account, new_size - old_size);
3572 rlm.verify_account_ram_usage(account);
3573}
3574
3576
3577template<>
3578void controller_impl::on_activation<builtin_protocol_feature_t::preactivate_feature>() {
3579 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3580 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "preactivate_feature" );
3581 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "is_feature_activated" );
3582 } );
3583}
3584
3585template<>
3586void controller_impl::on_activation<builtin_protocol_feature_t::get_sender>() {
3587 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3588 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_sender" );
3589 } );
3590}
3591
3592template<>
3593void controller_impl::on_activation<builtin_protocol_feature_t::replace_deferred>() {
3594 const auto& indx = db.get_index<account_ram_correction_index, by_id>();
3595 for( auto itr = indx.begin(); itr != indx.end(); itr = indx.begin() ) {
3596 int64_t current_ram_usage = resource_limits.get_account_ram_usage( itr->name );
3597 int64_t ram_delta = -static_cast<int64_t>(itr->ram_correction);
3598 if( itr->ram_correction > static_cast<uint64_t>(current_ram_usage) ) {
3599 ram_delta = -current_ram_usage;
3600 elog( "account ${name} was to be reduced by ${adjust} bytes of RAM despite only using ${current} bytes of RAM",
3601 ("name", itr->name)("adjust", itr->ram_correction)("current", current_ram_usage) );
3602 }
3603
3604 if (auto dm_logger = get_deep_mind_logger()) {
3605 dm_logger->on_ram_trace(RAM_EVENT_ID("${id}", ("id", itr->id._id)), "deferred_trx", "correction", "deferred_trx_ram_correction");
3606 }
3607
3608 resource_limits.add_pending_ram_usage( itr->name, ram_delta );
3609 db.remove( *itr );
3610 }
3611}
3612
3613template<>
3614void controller_impl::on_activation<builtin_protocol_feature_t::webauthn_key>() {
3615 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3616 ps.num_supported_key_types = 3;
3617 } );
3618}
3619
3620template<>
3621void controller_impl::on_activation<builtin_protocol_feature_t::em_key>() {
3622 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3623 ps.num_supported_key_types = 4;
3624 } );
3625}
3626
3627
3628template<>
3629void controller_impl::on_activation<builtin_protocol_feature_t::wtmsig_block_signatures>() {
3630 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3631 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_proposed_producers_ex" );
3632 } );
3633}
3634
3635template<>
3636void controller_impl::on_activation<builtin_protocol_feature_t::action_return_value>() {
3637 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3638 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_action_return_value" );
3639 } );
3640}
3641
3642template<>
3643void controller_impl::on_activation<builtin_protocol_feature_t::configurable_wasm_limits>() {
3644 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3645 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_wasm_parameters_packed" );
3646 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_wasm_parameters_packed" );
3647 } );
3648}
3649
3650template<>
3651void controller_impl::on_activation<builtin_protocol_feature_t::blockchain_parameters>() {
3652 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3653 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_parameters_packed" );
3654 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_parameters_packed" );
3655 } );
3656}
3657
3658template<>
3659void controller_impl::on_activation<builtin_protocol_feature_t::get_code_hash>() {
3660 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3661 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_code_hash" );
3662 } );
3663}
3664
3665template<>
3666void controller_impl::on_activation<builtin_protocol_feature_t::get_block_num>() {
3667 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3668 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "get_block_num" );
3669 } );
3670}
3671
3672template<>
3673void controller_impl::on_activation<builtin_protocol_feature_t::crypto_primitives>() {
3674 db.modify( db.get<protocol_state_object>(), [&]( auto& ps ) {
3675 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "alt_bn128_add" );
3676 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "alt_bn128_mul" );
3677 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "alt_bn128_pair" );
3678 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "mod_exp" );
3679 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "blake2_f" );
3680 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "sha3" );
3681 add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "k1_recover" );
3682 } );
3683}
3684
3686
3687} }
const mie::Vuint & p
Definition bn.cpp:27
const mie::Vuint & r
Definition bn.cpp:28
std::string name
constexpr uint64_t SYS_PERCENT(uint64_t value, uint32_t percentage)
Definition config.hpp:152
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
int64_t revision() const
void set_revision(uint64_t revision)
const generic_index< MultiIndexType > & get_index() const
pinnable_mapped_file::segment_manager * get_segment_manager()
void modify(const ObjectType &obj, Modifier &&m)
const ObjectType * find(CompatibleKey &&key) const
session start_undo_session(bool enabled)
Definition chainbase.cpp:73
void remove(const ObjectType &obj)
void commit(int64_t revision)
Definition chainbase.cpp:57
const ObjectType & create(Constructor &&con)
generic_index< MultiIndexType > & get_mutable_index()
const ObjectType & get(CompatibleKey &&key) const
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
int64_t code() const
const char * what() const noexcept override
constexpr int64_t count() const
Definition time.hpp:26
static constexpr microseconds maximum()
Definition time.hpp:14
wraps boost::filesystem::path to provide platform independent path manipulation.
static sha256 hash(const char *d, uint32_t dlen)
Definition sha256.cpp:44
static std_exception_wrapper from_current_exception(const std::exception &e)
static time_point now()
Definition time.cpp:14
static constexpr time_point maximum()
Definition time.hpp:46
void add_to_snapshot(const snapshot_writer_ptr &snapshot) const
void read_from_snapshot(const snapshot_reader_ptr &snapshot)
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,...
const permission_object & get_permission(const permission_level &level) const
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())
const block_id_type & head_id() const
signed_block_ptr read_block_by_num(uint32_t block_num) const
uint32_t first_block_num() const
void append(const signed_block_ptr &b)
const signed_block_ptr & head() const
void reset(const genesis_state &gs, const signed_block_ptr &genesis_block)
tracks minimal information about past blocks to implement TaPOS
void set_greylist_limit(uint32_t limit)
block_state_ptr fetch_block_state_by_number(uint32_t block_num) const
signal< void(const transaction_metadata_ptr &)> accepted_transaction
void set_actor_whitelist(const flat_set< account_name > &)
const flat_set< account_name > & get_actor_blacklist() const
void check_action_list(account_name code, action_name action) const
signal< void(const block_state_ptr &)> accepted_block_header
bool is_protocol_feature_activated(const digest_type &feature_digest) const
const global_property_object & get_global_properties() const
const chainbase::database & db() const
bool is_producing_block() const
bool is_trusted_producer(const account_name &producer) const
validation_mode get_validation_mode() const
signed_block_ptr fetch_block_by_number(uint32_t block_num) const
const dynamic_global_property_object & get_dynamic_global_properties() const
account_name fork_db_pending_head_block_producer() const
block_id_type fork_db_pending_head_block_id() const
void set_actor_blacklist(const flat_set< account_name > &)
static std::optional< chain_id_type > extract_chain_id_from_db(const path &state_dir)
signal< void(const block_state_ptr &)> accepted_block
void add_to_ram_correction(account_name account, uint64_t ram_bytes)
signal< void(const block_state_ptr &)> irreversible_block
db_read_mode get_read_mode() const
static chain_id_type extract_chain_id(snapshot_reader &snapshot)
vector< transaction_metadata_ptr > abort_block()
account_name head_block_producer() const
transaction_trace_ptr push_transaction(const transaction_metadata_ptr &trx, fc::time_point deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time, int64_t subjective_cpu_bill_us)
block_state_ptr create_block_state(const block_id_type &id, const signed_block_ptr &b) const
uint32_t head_block_num() const
void push_block(const block_state_ptr &bsp, const forked_branch_callback &cb, const trx_meta_cache_lookup &trx_lookup)
block_id_type head_block_id() const
void preactivate_feature(const digest_type &feature_digest)
std::optional< producer_authority_schedule > proposed_producers() const
void validate_expiration(const transaction &t) const
block_state_ptr head_block_state() const
void write_snapshot(const snapshot_writer_ptr &snapshot)
bool is_profiling(account_name name) const
uint32_t pending_block_num() const
const apply_handler * find_apply_handler(account_name contract, scope_name scope, action_name act) const
bool is_ram_billing_in_notify_allowed() const
authorization_manager & get_mutable_authorization_manager()
deep_mind_handler * get_deep_mind_logger() const
signal< void(const signed_block_ptr &)> pre_accepted_block
uint32_t last_irreversible_block_num() const
const producer_authority_schedule & pending_producers() const
void set_key_blacklist(const flat_set< public_key_type > &)
void set_s_header(const s_header &)
uint32_t fork_db_pending_head_block_num() const
uint32_t get_max_nonprivileged_inline_action_size() const
boost::asio::io_context & get_thread_pool()
block_id_type fork_db_head_block_id() const
const protocol_feature_manager & get_protocol_feature_manager() const
uint32_t configured_subjective_signature_length_limit() const
bool light_validation_allowed() const
void replace_account_keys(name account, name permission, const public_key_type &key)
account_name fork_db_head_block_producer() const
const flat_set< account_name > & get_contract_whitelist() const
account_name pending_block_producer() const
const block_signing_authority & pending_block_signing_authority() const
void validate_db_available_size() const
signed_block_ptr fetch_block_by_id(block_id_type id) const
time_point fork_db_head_block_time() const
void enable_deep_mind(deep_mind_handler *logger)
time_point last_irreversible_block_time() const
wasm_interface & get_wasm_interface()
const flat_set< pair< account_name, action_name > > & get_action_blacklist() 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)
@ irreversible
this block has already been applied before by this node and is considered irreversible
@ validated
this is a complete block signed by a valid producer and has been previously applied by this node and ...
@ complete
this is a complete block signed by a valid producer but is not yet irreversible nor has it yet been a...
uint32_t get_terminate_at_block() const
const authorization_manager & get_authorization_manager() const
void set_contract_blacklist(const flat_set< account_name > &)
block_state_ptr finalize_block(const signer_callback_type &signer_callback)
void validate_tapos(const transaction &t) const
block_id_type last_irreversible_block_id() const
const flat_set< account_name > & get_contract_blacklist() const
block_id_type get_block_id_for_num(uint32_t block_num) const
uint32_t get_greylist_limit() const
void remove_resource_greylist(const account_name &name)
bool is_resource_greylisted(const account_name &name) const
void check_key_list(const public_key_type &key) const
void check_actor_list(const flat_set< account_name > &actors) const
chain_id_type get_chain_id() const
bool is_builtin_activated(builtin_protocol_feature_t f) const
bool sender_avoids_whitelist_blacklist_enforcement(account_name sender) const
const flat_set< public_key_type > & get_key_blacklist() const
const flat_set< account_name > & get_resource_greylist() const
transaction_trace_ptr push_scheduled_transaction(const transaction_id_type &scheduled, fc::time_point block_deadline, fc::microseconds max_transaction_time, uint32_t billed_cpu_time_us, bool explicit_billed_cpu_time)
const account_object & get_account(account_name n) const
void set_contract_whitelist(const flat_set< account_name > &)
int64_t set_proposed_producers(vector< producer_authority > producers)
uint32_t earliest_available_block_num() const
time_point fork_db_pending_head_block_time() const
time_point pending_block_time() const
void validate_protocol_features(const vector< digest_type > &features_to_activate) const
signal< void(std::tuple< const transaction_trace_ptr &, const packed_transaction_ptr & >)> applied_transaction
vector< digest_type > get_preactivated_protocol_features() const
void set_subjective_cpu_leeway(fc::microseconds leeway)
void replace_producer_keys(const public_key_type &key)
block_state_ptr fetch_block_state_by_id(block_id_type id) const
void add_resource_greylist(const account_name &name)
const block_header & head_block_header() const
bool is_known_unexpired_transaction(const transaction_id_type &id) const
std::future< block_state_ptr > create_block_state_future(const block_id_type &id, const signed_block_ptr &b)
const vector< transaction_receipt > & get_pending_trx_receipts() const
signal< void(uint32_t)> block_start
resource_limits_manager & get_mutable_resource_limits_manager()
const fork_database & fork_db() const
const producer_authority_schedule & active_producers() const
uint32_t fork_db_head_block_num() const
const flat_set< account_name > & get_actor_whitelist() const
static std::optional< uint64_t > convert_exception_to_error_code(const fc::exception &e)
time_point head_block_time() const
const resource_limits_manager & get_resource_limits_manager() const
controller_impl
void set_action_blacklist(const flat_set< pair< account_name, action_name > > &)
std::optional< fc::microseconds > get_subjective_cpu_leeway() const
bool all_subjective_mitigations_disabled() const
void startup(std::function< void()> shutdown, std::function< bool()> check_shutdown, const snapshot_reader_ptr &snapshot)
controller(const config &cfg, const chain_id_type &chain_id)
void start_block(block_timestamp_type time=block_timestamp_type(), uint16_t confirm_block_count=0)
void check_contract_list(account_name code) const
tracks the version of the application data stored in the database
Maintains global state information that frequently change.
manages light-weight state for all potential unconfirmed forks
block_state_ptr pending_head() const
block_state_ptr search_on_branch(const block_id_type &h, uint32_t block_num) const
branch_type fetch_branch(const block_id_type &h, uint32_t trim_after_block_num=std::numeric_limits< uint32_t >::max()) const
void remove(const block_id_type &id)
fetch_branch_from_impl
block_state_ptr root() const
void open(const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> &validator)
block_state_ptr head() const
block_header_state_ptr get_block_header(const block_id_type &id) const
void mark_valid(const block_state_ptr &h)
pair< branch_type, branch_type > fetch_branch_from(const block_id_type &first, const block_id_type &second) const
void reset(const block_header_state &root_bhs)
void add(const block_state_ptr &next_block, bool ignore_duplicate=false)
void advance_root(const block_id_type &id)
block_state_ptr get_block(const block_id_type &id) const
time_point published
this generated transaction will not be applied after this time
Maintains global state information about block producer schedules and chain configuration parameters.
static void walk(const chainbase::database &db, F function)
static void create(chainbase::database &db, F cons)
maybe_session & operator=(maybe_session &&mv)
maybe_session(const maybe_session &)=delete
maybe_session(maybe_session &&other)
boost::asio::io_context & get_executor()
const protocol_feature_set & get_protocol_feature_set() const
void activate_feature(const digest_type &feature_digest, uint32_t current_block_num)
Maintains global state information about consensus protocol rules.
shared_vector< digest_type > preactivated_protocol_features
void read_from_snapshot(const snapshot_reader_ptr &snapshot)
void set_block_parameters(const elastic_limit_parameters &cpu_limit_parameters, const elastic_limit_parameters &net_limit_parameters)
void add_to_snapshot(const snapshot_writer_ptr &snapshot) const
void add_pending_ram_usage(const account_name account, int64_t ram_delta)
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)
int64_t get_account_ram_usage(const account_name &name) const
void verify_account_ram_usage(const account_name accunt) const
The table_id_object class tracks the mapping of (scope, code, table) to an opaque identifier.
void init_for_deferred_trx(fc::time_point published)
uint32_t update_billed_cpu_time(fc::time_point now)
void init_for_implicit_trx(uint64_t initial_net_usage=0)
vector< digest_type > executed_action_receipt_digests
flat_set< account_name > bill_to_accounts
std::tuple< int64_t, int64_t, bool, bool > max_bandwidth_billed_accounts_can_pay(bool force_elastic_limits=false) const
void init_for_input_trx(uint64_t packed_trx_unprunable_size, uint64_t packed_trx_prunable_size)
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)
void current_lib(const uint32_t lib)
uint64_t id
Definition code_cache.cpp:0
#define SET_APP_HANDLER(receiver, contract, action)
#define SYS_REPORT(DESC, A, B)
#define RAM_EVENT_ID(FORMAT,...)
Definition deep_mind.hpp:27
#define FC_CAPTURE_AND_RETHROW(...)
#define FC_LOG_AND_RETHROW()
void init()
Definition lib_test.cpp:3
#define wlog(FORMAT,...)
Definition logger.hpp:124
#define edump(SEQ)
Definition logger.hpp:162
#define dlog(FORMAT,...)
Definition logger.hpp:101
#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
void pack(Stream &s, const std::deque< T > &value)
Definition raw.hpp:531
void move_append(Container &dest, Container &&src)
Definition utility.hpp:151
scoped_exit< Callback > make_scoped_exit(Callback &&c)
@ read_write
@ read_only
constexpr microseconds seconds(int64_t s)
Definition time.hpp:32
Definition name.hpp:106
constexpr uint64_t billable_size_v
Definition config.hpp:147
const std::vector< const char * > genesis_intrinsics
std::future< transaction_metadata_ptr > recover_keys_future
chainbase::shared_multi_index_container< global_property_object, indexed_by< ordered_unique< tag< by_id >, > > > global_property_multi_index
chainbase::shared_multi_index_container< code_object, indexed_by< ordered_unique< tag< by_id >, member< code_object, code_object::id_type, &code_object::id > >, ordered_unique< tag< by_code_hash >, composite_key< code_object, member< code_object, digest_type, &code_object::code_hash >, member< code_object, uint8_t, &code_object::vm_type >, member< code_object, uint8_t, &code_object::vm_version > > > > > code_index
chainbase::shared_multi_index_container< account_object, indexed_by< ordered_unique< tag< by_id >, member< account_object, account_object::id_type, &account_object::id > >, ordered_unique< tag< by_name >, member< account_object, account_name, &account_object::name > > > > account_index
chainbase::shared_multi_index_container< block_summary_object, indexed_by< ordered_unique< tag< by_id >, BOOST_MULTI_INDEX_MEMBER(block_summary_object, block_summary_object::id_type, id)> > > block_summary_multi_index
std::function< std::vector< signature_type >(const digest_type &)> signer_callback_type
void add_intrinsic_to_whitelist(whitelisted_intrinsics_type &whitelisted_intrinsics, std::string_view name)
secondary_index< uint128_t, index128_object_type >::index_index index128_index
fc::sha256 block_id_type
Definition types.hpp:231
chainbase::shared_multi_index_container< account_ram_correction_object, indexed_by< ordered_unique< tag< by_id >, member< account_ram_correction_object, account_ram_correction_object::id_type, &account_ram_correction_object::id > >, ordered_unique< tag< by_name >, member< account_ram_correction_object, account_name, &account_ram_correction_object::name > > > > account_ram_correction_index
std::variant< building_block, assembled_block, completed_block > block_stage_type
std::shared_ptr< transaction_trace > transaction_trace_ptr
Definition trace.hpp:20
typename object_to_table_id_tag< T >::tag_type object_to_table_id_tag_t
std::variant< block_signing_authority_v0 > block_signing_authority
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
secondary_index< float64_t, index_double_object_type, soft_double_less >::index_index index_double_index
secondary_index< uint64_t, index64_object_type >::index_index index64_index
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
std::shared_ptr< const packed_transaction > packed_transaction_ptr
sysio::chain::action_name action_name
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
auto async_thread_pool(boost::asio::io_context &thread_pool, F &&f)
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
chainbase::shared_multi_index_container< dynamic_global_property_object, indexed_by< ordered_unique< tag< by_id >, > > > dynamic_global_property_multi_index
std::shared_ptr< snapshot_writer > snapshot_writer_ptr
Definition snapshot.hpp:155
digest_type merkle(vector< digest_type > ids)
Definition merkle.cpp:35
secondary_index< key256_t, index256_object_type >::index_index index256_index
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
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
std::shared_ptr< signed_block > signed_block_ptr
Definition block.hpp:105
unsigned char sysio_abi_bin[2132]
std::shared_ptr< snapshot_reader > snapshot_reader_ptr
Definition snapshot.hpp:294
chainbase::shared_multi_index_container< key_value_object, indexed_by< ordered_unique< tag< by_id >, member< key_value_object, key_value_object::id_type, &key_value_object::id > >, ordered_unique< tag< by_scope_primary >, composite_key< key_value_object, member< key_value_object, table_id, &key_value_object::t_id >, member< key_value_object, uint64_t, &key_value_object::primary_key > >, composite_key_compare< std::less< table_id >, std::less< uint64_t > > > > > key_value_index
chainbase::shared_multi_index_container< table_id_object, indexed_by< ordered_unique< tag< by_id >, member< table_id_object, table_id_object::id_type, &table_id_object::id > >, ordered_unique< tag< by_code_scope_table >, composite_key< table_id_object, member< table_id_object, account_name, &table_id_object::code >, member< table_id_object, scope_name, &table_id_object::scope >, member< table_id_object, table_name, &table_id_object::table > > > > > table_id_multi_index
chainbase::shared_multi_index_container< protocol_state_object, indexed_by< ordered_unique< tag< by_id >, > > > protocol_state_multi_index
std::function< void(apply_context &)> apply_handler
std::shared_ptr< block_state > block_state_ptr
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type fork_database_exception
std::shared_ptr< transaction_metadata > transaction_metadata_ptr
std::function< transaction_metadata_ptr(const transaction_id_type &)> trx_meta_cache_lookup
std::function< void(const branch_type &)> forked_branch_callback
chainbase::shared_multi_index_container< account_metadata_object, indexed_by< ordered_unique< tag< by_id >, member< account_metadata_object, account_metadata_object::id_type, &account_metadata_object::id > >, ordered_unique< tag< by_name >, member< account_metadata_object, account_name, &account_metadata_object::name > > > > account_metadata_index
secondary_index< float128_t, index_long_double_object_type, soft_long_double_less >::index_index index_long_double_index
fc::logger logger
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1181
#define T(meth, val, expected)
schedule config_dir_name data_dir_name p2p_port http_port file_size name name keys peers producers(dont_start)) FC_REFLECT(testnet_def
const std::set< std::string > blacklist
unsigned short uint16_t
Definition stdint.h:125
signed __int64 int64_t
Definition stdint.h:135
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
uint32_t value
Definition varint.hpp:17
vector< permission_level > authorization
Definition action.hpp:59
pending_block_header_state _pending_block_header_state
vector< transaction_metadata_ptr > _trx_metas
std::optional< producer_authority_schedule > _new_producer_authority_cache
signed_block_ptr _unsigned_block
vector< permission_level_weight > accounts
defines the minimum state necessary to validate transaction headers
protocol_feature_activation_set_ptr activated_protocol_features
block_timestamp_type timestamp
checksum256_type transaction_mroot
static uint32_t num_from_id(const block_id_type &id)
checksum256_type action_mroot
mroot of cycles_summary
extensions_type header_extensions
block_id_type calculate_id() const
new_producers_type new_producers
std::optional< checksum256_type > _transaction_mroot
size_t _num_new_protocol_features_that_have_activated
std::optional< s_header > _s_header
vector< transaction_metadata_ptr > _pending_trx_metas
vector< digest_type > _new_protocol_feature_activations
pending_block_header_state _pending_block_header_state
vector< digest_type > _action_receipt_digests
building_block(const block_header_state &prev, block_timestamp_type when, uint16_t num_prev_blocks_to_confirm, const vector< digest_type > &new_protocol_feature_activations)
std::optional< producer_authority_schedule > _new_pending_producer_schedule
vector< transaction_receipt > _pending_trx_receipts
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
uint32_t min_transaction_cpu_usage
the minimum billable cpu usage (in microseconds) that the chain requires
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...
v1 Producer-voted blockchain configuration parameters
flat_set< account_name > contract_whitelist
flat_set< account_name > actor_blacklist
flat_set< account_name > actor_whitelist
flat_set< account_name > contract_blacklist
flat_set< account_name > sender_bypass_whiteblacklist
flat_set< pair< account_name, action_name > > action_blacklist
flat_set< public_key_type > key_blacklist
void initialize_database(const genesis_state &genesis)
std::optional< pending_state > pending
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 check_contract_list(account_name code) const
void startup(std::function< void()> shutdown, std::function< bool()> check_shutdown, const snapshot_reader_ptr &snapshot)
deep_mind_handler * get_deep_mind_logger() const
int64_t remove_scheduled_transaction(const generated_transaction_object &gto)
void read_from_snapshot(const snapshot_reader_ptr &snapshot, uint32_t blog_start, uint32_t blog_end)
protocol_feature_manager protocol_features
block_state_ptr create_block_state_i(const block_id_type &id, const signed_block_ptr &b, const block_header_state &prev)
apply_block
const chain_id_type chain_id
void replay_push_block(const signed_block_ptr &b, controller::block_status s)
void clear_expired_input_transactions(const fc::time_point &deadline)
signed_transaction get_on_block_transaction()
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)
deep_mind_handler * deep_mind_logger
void finalize_block()
start_block
static std::optional< genesis_state > extract_legacy_genesis_state(snapshot_reader &snapshot, uint32_t version)
void emit(const Signal &s, Arg &&a)
map< account_name, map< handler_key, apply_handler > > apply_handlers
void create_block_summary(const block_id_type &id)
void startup(std::function< void()> shutdown, std::function< bool()> check_shutdown, const genesis_state &genesis)
std::function< void()> shutdown
pair< scope_name, action_name > handler_key
resource_limits_manager resource_limits
void add_to_snapshot(const snapshot_writer_ptr &snapshot)
uint32_t earliest_available_block_num() const
void set_apply_handler(account_name receiver, account_name contract, action_name action, apply_handler v)
fc::scoped_exit< std::function< void()> > make_block_restore_point()
void dmlog_applied_transaction(const transaction_trace_ptr &t)
void initialize_blockchain_state(const genesis_state &genesis)
void startup(std::function< void()> shutdown, std::function< bool()> check_shutdown)
void trigger_activation_handler(builtin_protocol_feature_t f)
void replay(std::function< bool()> check_shutdown)
static checksum256_type calculate_trx_merkle(const vector< transaction_receipt > &trxs)
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 init(std::function< bool()> check_shutdown)
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)
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
void apply_block(const block_state_ptr &bsp, controller::block_status s, const trx_meta_cache_lookup &trx_lookup)
bool in_trx_requiring_checks
if true, checks that are normally skipped on replay (e.g. auth checks) cannot be skipped
void read_contract_tables_from_snapshot(const snapshot_reader_ptr &snapshot)
named_thread_pool thread_pool
authorization_manager authorization
bool scheduled_failure_is_subjective(const fc::exception &e) const
std::optional< fc::microseconds > subjective_cpu_leeway
void commit_block(bool add_to_fork_db)
finalize_block
void push_block(const block_state_ptr &bsp, const forked_branch_callback &forked_branch_cb, const trx_meta_cache_lookup &trx_lookup)
void check_actor_list(const flat_set< account_name > &actors) const
unordered_map< builtin_protocol_feature_t, std::function< void(controller_impl &)>, enum_hash< builtin_protocol_feature_t > > protocol_feature_activation_handlers
bool failure_is_subjective(const fc::exception &e) const
block_state_ptr create_block_state(const block_id_type &id, const signed_block_ptr &b)
void check_key_list(const public_key_type &key) const
static auto validate_db_version(const chainbase::database &db)
void create_native_account(const fc::time_point &initial_timestamp, account_name name, const authority &owner, const authority &active, bool is_privileged=false)
void check_protocol_features(block_timestamp_type timestamp, const flat_set< digest_type > &currently_activated_protocol_features, const vector< digest_type > &new_protocol_features)
bool sender_avoids_whitelist_blacklist_enforcement(account_name sender) const
vector< transaction_metadata_ptr > abort_block()
push_block
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)
std::future< block_state_ptr > create_block_state_future(const block_id_type &id, const signed_block_ptr &b)
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)
void add_contract_tables_to_snapshot(const snapshot_writer_ptr &snapshot) const
controller_impl(const controller::config &cfg, controller &s, protocol_feature_set &&pfs, const chain_id_type &chain_id)
void check_action_list(account_name code, action_name action) const
producer_authority_schedule schedule
digest_type schedule_hash
last irr block num
static constexpr wasm_config default_initial_wasm_configuration
limits for a kv database.
Definition kv_config.hpp:15
Immutable except for fc::from_variant.
Definition name.hpp:43
const transaction & get_transaction() const
pending_state(maybe_session &&s, const block_header_state &prev, block_timestamp_type when, uint16_t num_prev_blocks_to_confirm, const vector< digest_type > &new_protocol_feature_activations)
const pending_block_header_state & get_pending_block_header_state() const
bool is_protocol_feature_activated(const digest_type &feature_digest) const
vector< transaction_metadata_ptr > extract_trx_metas()
std::optional< block_id_type > _producer_block_id
const vector< transaction_receipt > & get_trx_receipts() const
block_stage_type _block_stage
controller::block_status _block_status
uint32_t version
sequentially incrementing version number
static auto from_shared(const shared_producer_authority_schedule &src)
auto to_shared(chainbase::allocator< char > alloc) const
std::string to_string() const
void set_reference_block(const block_id_type &reference_block)
fc::unsigned_int delay_sec
upper limit on the total CPU time billed for this transaction
uint16_t ref_block_num
specifies a block num in the last 2^16 blocks.
uint32_t ref_block_prefix
specifies the lower 32 bits of the blockid at get_ref_blocknum
bool verify_reference_block(const block_id_type &reference_block) const
time_point_sec expiration
the time at which a transaction expires
@ delayed
transaction delayed/deferred/scheduled for future execution
Definition block.hpp:17
@ executed
succeed, no error handler executed
Definition block.hpp:14
@ soft_fail
objectively failed (not executed), error handler executed
Definition block.hpp:15
@ hard_fail
objectively failed and error handler objectively failed thus no state change
Definition block.hpp:16
@ expired
transaction expired and storage space refuned to user
Definition block.hpp:18
vector< action > actions
uint8_t key[16]
Definition yubico_otp.c:41
CK_ULONG d
char * s