提交 c7a81963 编写于 作者: D Daniel Larimer

clean up controller

上级 200177ec
......@@ -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} )
......@@ -35,6 +35,36 @@
#include <chrono>
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<block_id_type> 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<fc::exception> 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<account_index>();
_db.add_index<permission_index>();
_db.add_index<permission_link_index>();
......@@ -760,7 +790,7 @@ void chain_controller::initialize_indexes() {
_db.add_index<producer_multi_index>();
}
void chain_controller::initialize_chain(contracts::chain_initializer& starter)
void chain_controller::_initialize_chain(contracts::chain_initializer& starter)
{ try {
if (!_db.find<global_property_object>()) {
_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 << "% "<<i << " of " <<last_block_num<<" \n";
fc::optional<signed_block> 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<signed_block> 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
......@@ -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<uint16_t IntervalMs, uint64_t EpochMs>
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<config::block_interval_ms,config::block_timestamp_epoch> block_timestamp_type;
template<uint16_t IntervalMs, uint64_t EpochMs>
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<config::block_interval_ms,config::block_timestamp_epoch> block_timestamp_type;
} } /// eosio::chain
......@@ -76,15 +72,12 @@ FC_REFLECT(eosio::chain::block_timestamp_type, (slot))
namespace fc {
template<uint16_t IntervalMs, uint64_t EpochMs>
void to_variant(const eosio::chain::block_timestamp<IntervalMs,EpochMs>& t, fc::variant& v) {
auto tp = (fc::time_point)t;
to_variant(tp, v);
to_variant( (fc::time_point)t, v);
}
template<uint16_t IntervalMs, uint64_t EpochMs>
void from_variant(const fc::variant& v, eosio::chain::block_timestamp<IntervalMs,EpochMs>& t) {
fc::microseconds mc;
from_variant(v, mc);
t = fc::time_point(mc);
t = v.as<fc::time_point>();
}
}
......
......@@ -17,6 +17,7 @@
#include <eosio/chain/protocol.hpp>
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/contracts/genesis_state.hpp>
#include <fc/log/logger.hpp>
......@@ -25,24 +26,53 @@
namespace eosio { namespace chain {
using database = chainbase::database;
using boost::signals2::signal;
using applied_irreverisable_block_func = fc::optional<signal<void(const signed_block&)>::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<void(const signed_transaction&)> 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<uint32_t,block_id_type> 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<signed_transaction>& 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<typename Function>
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<database::session> _pending_block_session;
optional<signed_block> _pending_block;
......
......@@ -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);
......
......@@ -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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册