From c7a8196370741b50e2dc10b16d3ae0c83e33442a Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 10 Nov 2017 23:13:27 -0500 Subject: [PATCH] clean up controller --- libraries/chain/CMakeLists.txt | 3 + libraries/chain/chain_controller.cpp | 101 +++++++------- .../include/eosio/chain/block_timestamp.hpp | 109 +++++++-------- .../include/eosio/chain/chain_controller.hpp | 129 +++++++++++------- .../chain/include/eosio/chain/config.hpp | 3 + libraries/chain/include/eosio/chain/types.hpp | 2 + 6 files changed, 184 insertions(+), 163 deletions(-) diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 4c35a2fd9..77bde4cd0 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -45,3 +45,6 @@ INSTALL( TARGETS ARCHIVE DESTINATION lib ) INSTALL( FILES ${HEADERS} DESTINATION "include/eos/chain" ) + +add_executable( test test.cpp ) +target_link_libraries( test eos_chain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ${Intl_LIBRARIES} ) diff --git a/libraries/chain/chain_controller.cpp b/libraries/chain/chain_controller.cpp index 6a3f9600c..ff2c9dd96 100644 --- a/libraries/chain/chain_controller.cpp +++ b/libraries/chain/chain_controller.cpp @@ -35,6 +35,36 @@ #include namespace eosio { namespace chain { + +chain_controller::chain_controller( const chain_controller::controller_config& cfg ) +:_db( cfg.shared_memory_dir, + (cfg.read_only ? database::read_only : database::read_write), + cfg.shared_memory_size), + _block_log(cfg.block_log_dir) +{ + _initialize_indexes(); + + contracts::chain_initializer starter(cfg.genesis); + starter.register_types(*this, _db); + + // Behave as though we are applying a block during chain initialization (it's the genesis block!) + with_applying_block([&] { + _initialize_chain(starter); + }); + + _spinup_db(); + _spinup_fork_db(); + + if (_block_log.read_head() && head_block_num() < _block_log.read_head()->block_num()) + replay(); +} /// chain_controller::chain_controller + + +chain_controller::~chain_controller() { + clear_pending(); + _db.flush(); +} + bool chain_controller::is_known_block(const block_id_type& id)const { return _fork_db.is_known_block(id) || _block_log.read_block_by_id(id); @@ -117,9 +147,9 @@ std::vector chain_controller::get_block_ids_on_fork(block_id_type * * @return true if we switched forks as a result of this push. */ -bool chain_controller::push_block(const signed_block& new_block, uint32_t skip) +void chain_controller::push_block(const signed_block& new_block, uint32_t skip) { try { - return with_skip_flags( skip, [&](){ + with_skip_flags( skip, [&](){ return without_pending_transactions( [&]() { return _db.with_write_lock( [&]() { return _push_block(new_block); @@ -154,7 +184,7 @@ bool chain_controller::_push_block(const signed_block& new_block) optional except; try { auto session = _db.start_undo_session(true); - apply_block((*ritr)->data, skip); + _apply_block((*ritr)->data, skip); session.push(); } catch (const fc::exception& e) { except = e; } @@ -174,21 +204,21 @@ bool chain_controller::_push_block(const signed_block& new_block) // restore all blocks from the good fork for (auto ritr = branches.second.rbegin(); ritr != branches.second.rend(); ++ritr) { auto session = _db.start_undo_session(true); - apply_block((*ritr)->data, skip); + _apply_block((*ritr)->data, skip); session.push(); } throw *except; } } - return true; + return true; //swithced fork } - else return false; + else return false; // didn't switch fork } } try { auto session = _db.start_undo_session(true); - apply_block(new_block, skip); + _apply_block(new_block, skip); session.push(); } catch ( const fc::exception& e ) { elog("Failed to push new block:\n${e}", ("e", e.to_detail_string())); @@ -324,7 +354,7 @@ void chain_controller::clear_pending() //////////////////// private methods //////////////////// -void chain_controller::apply_block(const signed_block& next_block, uint32_t skip) +void chain_controller::_apply_block(const signed_block& next_block, uint32_t skip) { auto block_num = next_block.block_num(); if (_checkpoints.size() && _checkpoints.rbegin()->second != block_id_type()) { @@ -339,13 +369,13 @@ void chain_controller::apply_block(const signed_block& next_block, uint32_t skip with_applying_block([&] { with_skip_flags(skip, [&] { - _apply_block(next_block); + __apply_block(next_block); }); }); } -void chain_controller::_apply_block(const signed_block& next_block) +void chain_controller::__apply_block(const signed_block& next_block) { try { uint32_t skip = _skip_flags; @@ -742,7 +772,7 @@ uint32_t chain_controller::last_irreversible_block_num() const { return get_dynamic_global_properties().last_irreversible_block_num; } -void chain_controller::initialize_indexes() { +void chain_controller::_initialize_indexes() { _db.add_index(); _db.add_index(); _db.add_index(); @@ -760,7 +790,7 @@ void chain_controller::initialize_indexes() { _db.add_index(); } -void chain_controller::initialize_chain(contracts::chain_initializer& starter) +void chain_controller::_initialize_chain(contracts::chain_initializer& starter) { try { if (!_db.find()) { _db.with_write_lock([this, &starter] { @@ -810,37 +840,6 @@ void chain_controller::initialize_chain(contracts::chain_initializer& starter) } } FC_CAPTURE_AND_RETHROW() } -chain_controller::chain_controller(database& database, fork_database& fork_db, block_log& blocklog, - contracts::chain_initializer& starter, - uint32_t txn_execution_time, uint32_t rcvd_block_txn_execution_time, - uint32_t create_block_txn_execution_time, - const applied_irreverisable_block_func& applied_func) -:_db(database), _fork_db(fork_db), _block_log(blocklog) -{ - - if (applied_func) - applied_irreversible_block.connect(*applied_func); - - initialize_indexes(); - starter.register_types(*this, _db); - - // Behave as though we are applying a block during chain initialization (it's the genesis block!) - with_applying_block([&] { - initialize_chain(starter); - }); - - spinup_db(); - spinup_fork_db(); - - if (_block_log.read_head() && head_block_num() < _block_log.read_head()->block_num()) - replay(); -} - -chain_controller::~chain_controller() { - clear_pending(); - _db.flush(); - _fork_db.reset(); -} void chain_controller::replay() { ilog("Replaying blockchain"); @@ -865,7 +864,7 @@ void chain_controller::replay() { std::cerr << " " << double(i*100)/last_block_num << "% "< block = _block_log.read_block_by_num(i); FC_ASSERT(block, "Could not find block #${n} in block_log!", ("n", i)); - apply_block(*block, skip_producer_signature | + _apply_block(*block, skip_producer_signature | skip_transaction_signatures | skip_transaction_dupe_check | skip_tapos_check | @@ -880,7 +879,7 @@ void chain_controller::replay() { _db.set_revision(head_block_num()); } -void chain_controller::spinup_db() { +void chain_controller::_spinup_db() { // Rewind the database to the last irreversible block _db.with_write_lock([&] { _db.undo_all(); @@ -890,7 +889,7 @@ void chain_controller::spinup_db() { }); } -void chain_controller::spinup_fork_db() +void chain_controller::_spinup_fork_db() { fc::optional last_block = _block_log.read_head(); if(last_block.valid()) { @@ -1089,12 +1088,8 @@ uint32_t chain_controller::producer_participation_rate()const return uint64_t(config::percent_100) * __builtin_popcountll(dpo.recent_slots_filled) / 64; } -void chain_controller::set_apply_handler( const account_name& contract, - const account_name& scope, - const action_name& action, apply_handler v ) { - - //apply_handlers[contract][std::make_pair(scope,action)] = v; +void chain_controller::_set_apply_handler( account_name contract, scope_name scope, action_name action, apply_handler v ) { + _apply_handlers[contract][make_pair(scope,action)] = v; } - -} } +} } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/block_timestamp.hpp b/libraries/chain/include/eosio/chain/block_timestamp.hpp index 95206bfc1..45d1ecf1f 100644 --- a/libraries/chain/include/eosio/chain/block_timestamp.hpp +++ b/libraries/chain/include/eosio/chain/block_timestamp.hpp @@ -9,63 +9,59 @@ namespace eosio { namespace chain { - /** + /** * This class is used in the block headers to represent the block time * It is a parameterised class that takes an Epoch in milliseconds and * and an interval in milliseconds and computes the number of slots. **/ - template - class block_timestamp { - public: - explicit block_timestamp( uint32_t s=0 ) :slot(s){} - - block_timestamp(const fc::time_point& t) { - set_time_point(t); - } - - block_timestamp(const fc::time_point_sec& t) { - set_time_point(t); - } - - static block_timestamp maximum() { return block_timestamp( 0xffff ); } - static block_timestamp min() { return block_timestamp(0); } - - operator fc::time_point() const { - int64_t msec = slot * (int64_t)IntervalMs; - msec += EpochMs; - return fc::time_point(fc::microseconds(msec * 1000)); - } - - void operator = (const fc::time_point& t ) { - set_time_point(t); - } - - void operator = (const fc::time_point_sec& t ) { - set_time_point(t); - } - - bool operator > ( const block_timestamp& t )const { return slot > t.slot; } - bool operator >=( const block_timestamp& t )const { return slot >= t.slot; } - bool operator < ( const block_timestamp& t )const { return slot < t.slot; } - bool operator <=( const block_timestamp& t )const { return slot <= t.slot; } - bool operator ==( const block_timestamp& t )const { return slot == t.slot; } - bool operator !=( const block_timestamp& t )const { return slot != t.slot; } - uint32_t slot; - - private: - void set_time_point(const fc::time_point& t) { - auto micro_since_epoch = t.time_since_epoch(); - auto msec_since_epoch = micro_since_epoch.count() / 1000; - slot = ( msec_since_epoch - EpochMs ) / IntervalMs; - } - - void set_time_point(const fc::time_point_sec& t) { - uint64_t sec_since_epoch = t.sec_since_epoch(); - slot = (sec_since_epoch * 1000 - EpochMs) / IntervalMs; - } - }; // block_timestamp - - typedef block_timestamp block_timestamp_type; + template + class block_timestamp { + public: + explicit block_timestamp( uint32_t s=0 ) :slot(s){} + + block_timestamp(const fc::time_point& t) { + set_time_point(t); + } + + block_timestamp(const fc::time_point_sec& t) { + set_time_point(t); + } + + static block_timestamp maximum() { return block_timestamp( 0xffff ); } + static block_timestamp min() { return block_timestamp(0); } + + operator fc::time_point() const { + int64_t msec = slot * (int64_t)IntervalMs; + msec += EpochMs; + return fc::time_point(fc::milliseconds(msec)); + } + + void operator = (const fc::time_point& t ) { + set_time_point(t); + } + + bool operator > ( const block_timestamp& t )const { return slot > t.slot; } + bool operator >=( const block_timestamp& t )const { return slot >= t.slot; } + bool operator < ( const block_timestamp& t )const { return slot < t.slot; } + bool operator <=( const block_timestamp& t )const { return slot <= t.slot; } + bool operator ==( const block_timestamp& t )const { return slot == t.slot; } + bool operator !=( const block_timestamp& t )const { return slot != t.slot; } + uint32_t slot; + + private: + void set_time_point(const fc::time_point& t) { + auto micro_since_epoch = t.time_since_epoch(); + auto msec_since_epoch = micro_since_epoch.count() / 1000; + slot = ( msec_since_epoch - EpochMs ) / IntervalMs; + } + + void set_time_point(const fc::time_point_sec& t) { + uint64_t sec_since_epoch = t.sec_since_epoch(); + slot = (sec_since_epoch * 1000 - EpochMs) / IntervalMs; + } + }; // block_timestamp + + typedef block_timestamp block_timestamp_type; } } /// eosio::chain @@ -76,15 +72,12 @@ FC_REFLECT(eosio::chain::block_timestamp_type, (slot)) namespace fc { template void to_variant(const eosio::chain::block_timestamp& t, fc::variant& v) { - auto tp = (fc::time_point)t; - to_variant(tp, v); + to_variant( (fc::time_point)t, v); } template void from_variant(const fc::variant& v, eosio::chain::block_timestamp& t) { - fc::microseconds mc; - from_variant(v, mc); - t = fc::time_point(mc); + t = v.as(); } } diff --git a/libraries/chain/include/eosio/chain/chain_controller.hpp b/libraries/chain/include/eosio/chain/chain_controller.hpp index bb9ea3283..6b0288a3c 100644 --- a/libraries/chain/include/eosio/chain/chain_controller.hpp +++ b/libraries/chain/include/eosio/chain/chain_controller.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include @@ -25,24 +26,53 @@ namespace eosio { namespace chain { using database = chainbase::database; using boost::signals2::signal; - using applied_irreverisable_block_func = fc::optional::slot_type>; - namespace contracts { class chain_initializer; } + namespace contracts{ class chain_initializer; } + + enum validation_steps + { + skip_nothing = 0, + skip_producer_signature = 1 << 0, ///< used while reindexing + skip_transaction_signatures = 1 << 1, ///< used by non-producer nodes + skip_transaction_dupe_check = 1 << 2, ///< used while reindexing + skip_fork_db = 1 << 3, ///< used while reindexing + skip_block_size_check = 1 << 4, ///< used when applying locally generated transactions + skip_tapos_check = 1 << 5, ///< used while reindexing -- note this skips expiration check as well + skip_authority_check = 1 << 6, ///< used while reindexing -- disables any checking of authority on transactions + skip_merkle_check = 1 << 7, ///< used while reindexing + skip_assert_evaluation = 1 << 8, ///< used while reindexing + skip_undo_history_check = 1 << 9, ///< used while reindexing + skip_producer_schedule_check= 1 << 10, ///< used while reindexing + skip_validate = 1 << 11, ///< used prior to checkpoint, skips validate() call on transaction + skip_scope_check = 1 << 12, ///< used to skip checks for proper scope + skip_output_check = 1 << 13, ///< used to skip checks for outputs in block exactly matching those created from apply + pushed_transaction = 1 << 14, ///< used to indicate that the origination of the call was from a push_transaction, to determine time allotment + created_block = 1 << 15, ///< used to indicate that the origination of the call was for creating a block, to determine time allotment + received_block = 1 << 16 ///< used to indicate that the origination of the call was for a received block, to determine time allotment + }; + /** * @class database * @brief tracks the blockchain state in an extensible manner */ - class chain_controller { + class chain_controller : public boost::noncopyable { public: - chain_controller(database& database, fork_database& fork_db, block_log& blocklog, - contracts::chain_initializer& starter, - uint32_t txn_execution_time, uint32_t rcvd_block_txn_execution_time, - uint32_t create_block_txn_execution_time, - const applied_irreverisable_block_func& applied_func = {}); - chain_controller(chain_controller&&) = default; + struct controller_config { + path block_log_dir = config::default_block_log_dir; + path shared_memory_dir = config::default_shared_memory_dir; + uint64_t shared_memory_size = config::default_shared_memory_size; + bool read_only = false; + contracts::genesis_state_type genesis; + }; + + chain_controller( const controller_config& cfg ); ~chain_controller(); + void push_block( const signed_block& b, uint32_t skip = skip_nothing ); + void push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing ); + + /** * This signal is emitted after all operations and virtual operation for a * block have been applied but before the get_applied_operations() are cleared. @@ -68,40 +98,24 @@ namespace eosio { namespace chain { */ signal on_pending_transaction; + + + + + + + + + + /** * @brief Check whether the controller is currently applying a block or not * @return True if the controller is now applying a block; false otherwise */ bool is_applying_block()const { return _currently_applying_block; } - /** - * The controller can override any script endpoint with native code. - */ - ///@{ - void set_apply_handler( const account_name& contract, const account_name& scope, const action_name& action, apply_handler v ); - //@} - enum validation_steps - { - skip_nothing = 0, - skip_producer_signature = 1 << 0, ///< used while reindexing - skip_transaction_signatures = 1 << 1, ///< used by non-producer nodes - skip_transaction_dupe_check = 1 << 2, ///< used while reindexing - skip_fork_db = 1 << 3, ///< used while reindexing - skip_block_size_check = 1 << 4, ///< used when applying locally generated transactions - skip_tapos_check = 1 << 5, ///< used while reindexing -- note this skips expiration check as well - skip_authority_check = 1 << 6, ///< used while reindexing -- disables any checking of authority on transactions - skip_merkle_check = 1 << 7, ///< used while reindexing - skip_assert_evaluation = 1 << 8, ///< used while reindexing - skip_undo_history_check = 1 << 9, ///< used while reindexing - skip_producer_schedule_check= 1 << 10, ///< used while reindexing - skip_validate = 1 << 11, ///< used prior to checkpoint, skips validate() call on transaction - skip_scope_check = 1 << 12, ///< used to skip checks for proper scope - skip_output_check = 1 << 13, ///< used to skip checks for outputs in block exactly matching those created from apply - pushed_transaction = 1 << 14, ///< used to indicate that the origination of the call was from a push_transaction, to determine time allotment - created_block = 1 << 15, ///< used to indicate that the origination of the call was for creating a block, to determine time allotment - received_block = 1 << 16 ///< used to indicate that the origination of the call was for a received block, to determine time allotment - }; + /** * @return true if the block is in our fork DB or saved to disk as @@ -131,10 +145,6 @@ namespace eosio { namespace chain { const flat_map get_checkpoints()const { return _checkpoints; } bool before_last_checkpoint()const; - bool push_block( const signed_block& b, uint32_t skip = skip_nothing ); - - - void push_transaction( const signed_transaction& trx, uint32_t skip = skip_nothing ); @@ -240,27 +250,42 @@ namespace eosio { namespace chain { uint32_t last_irreversible_block_num() const; - // protected: const chainbase::database& get_database() const { return _db; } - chainbase::database& get_mutable_database() { return _db; } + chainbase::database& get_mutable_database() { return _db; } - bool should_check_scope()const { return !(_skip_flags&skip_scope_check); } const deque& pending()const { return _pending_transactions; } + + + + + private: + friend class contracts::chain_initializer; + + bool should_check_scope()const { return !(_skip_flags&skip_scope_check); } + + /** + * The controller can override any script endpoint with native code. + */ + ///@{ + void _set_apply_handler( account_name contract, account_name scope, action_name action, apply_handler v ); + //@} + + void _push_transaction( const signed_transaction& trx ); void _start_pending_block(); void _apply_transaction( const transaction& trx ); /// Reset the object graph in-memory - void initialize_indexes(); - void initialize_chain(contracts::chain_initializer& starter); + void _initialize_indexes(); + void _initialize_chain(contracts::chain_initializer& starter); void replay(); - void apply_block(const signed_block& next_block, uint32_t skip = skip_nothing); - void _apply_block(const signed_block& next_block); + void _apply_block(const signed_block& next_block, uint32_t skip = skip_nothing); + void __apply_block(const signed_block& next_block); template auto with_applying_block(Function&& f) -> decltype((*((Function*)nullptr))()) { @@ -338,14 +363,14 @@ namespace eosio { namespace chain { void clear_expired_transactions(); /// @} - void spinup_db(); - void spinup_fork_db(); + void _spinup_db(); + void _spinup_fork_db(); // producer_schedule_type calculate_next_round( const signed_block& next_block ); - database& _db; - fork_database& _fork_db; - block_log& _block_log; + database _db; + fork_database _fork_db; + block_log _block_log; optional _pending_block_session; optional _pending_block; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 8892f1cbc..4dc93bf82 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -10,6 +10,9 @@ namespace eosio { namespace chain { namespace config { typedef __uint128_t uint128_t; +const static auto default_block_log_dir = "block_log"; +const static auto default_shared_memory_dir = "shared_mem"; +const static auto default_shared_memory_size = 1024*1024*1024ll; const static int producer_count = 21; const static uint64_t system_account_name = N(eosio); diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index bb9c5c94a..66116a469 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -55,12 +55,14 @@ namespace eosio { namespace chain { using std::unique_ptr; using std::set; using std::pair; + using std::make_pair; using std::enable_shared_from_this; using std::tie; using std::make_pair; using std::move; using std::forward; + using fc::path; using fc::smart_ref; using fc::variant_object; using fc::variant; -- GitLab