Progress #17: Lazy load genesis state
This speeds up startup for witness_node when starting on a database which is already initialized.
This commit is contained in:
parent
9c4ac2e064
commit
d64c9154a7
8 changed files with 86 additions and 75 deletions
|
|
@ -183,12 +183,14 @@ namespace detail {
|
||||||
bool clean = !fc::exists(_data_dir / "blockchain/dblock");
|
bool clean = !fc::exists(_data_dir / "blockchain/dblock");
|
||||||
fc::create_directories(_data_dir / "blockchain/dblock");
|
fc::create_directories(_data_dir / "blockchain/dblock");
|
||||||
|
|
||||||
genesis_state_type initial_state;
|
auto initial_state = [&] {
|
||||||
|
ilog("Initializing database...");
|
||||||
if( _options->count("genesis-json") )
|
if( _options->count("genesis-json") )
|
||||||
initial_state = fc::json::from_file(_options->at("genesis-json").as<boost::filesystem::path>())
|
return fc::json::from_file(_options->at("genesis-json").as<boost::filesystem::path>())
|
||||||
.as<genesis_state_type>();
|
.as<genesis_state_type>();
|
||||||
else
|
else
|
||||||
initial_state = create_example_genesis();
|
return create_example_genesis();
|
||||||
|
};
|
||||||
|
|
||||||
if( _options->count("resync-blockchain") )
|
if( _options->count("resync-blockchain") )
|
||||||
_chain_db->wipe(_data_dir / "blockchain", true);
|
_chain_db->wipe(_data_dir / "blockchain", true);
|
||||||
|
|
@ -196,12 +198,12 @@ namespace detail {
|
||||||
if( _options->count("replay-blockchain") )
|
if( _options->count("replay-blockchain") )
|
||||||
{
|
{
|
||||||
ilog("Replaying blockchain on user request.");
|
ilog("Replaying blockchain on user request.");
|
||||||
_chain_db->reindex(_data_dir/"blockchain", initial_state);
|
_chain_db->reindex(_data_dir/"blockchain", initial_state());
|
||||||
} else if( clean )
|
} else if( clean )
|
||||||
_chain_db->open(_data_dir / "blockchain", initial_state);
|
_chain_db->open(_data_dir / "blockchain", initial_state);
|
||||||
else {
|
else {
|
||||||
wlog("Detected unclean shutdown. Replaying blockchain...");
|
wlog("Detected unclean shutdown. Replaying blockchain...");
|
||||||
_chain_db->reindex(_data_dir / "blockchain", initial_state);
|
_chain_db->reindex(_data_dir / "blockchain", initial_state());
|
||||||
}
|
}
|
||||||
|
|
||||||
if( _options->count("apiaccess") )
|
if( _options->count("apiaccess") )
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
#include <graphene/chain/operation_history_object.hpp>
|
#include <graphene/chain/operation_history_object.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
database::database()
|
database::database()
|
||||||
|
|
@ -33,31 +35,10 @@ database::~database(){
|
||||||
_pending_block_session->commit();
|
_pending_block_session->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void database::open( const fc::path& data_dir, const genesis_state_type& initial_allocation )
|
|
||||||
{ try {
|
|
||||||
object_database::open( data_dir );
|
|
||||||
|
|
||||||
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
|
|
||||||
|
|
||||||
if( !find(global_property_id_type()) )
|
|
||||||
{
|
|
||||||
// ilog( "Init Genesis State" );
|
|
||||||
init_genesis(initial_allocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
_pending_block.previous = head_block_id();
|
|
||||||
_pending_block.timestamp = head_block_time();
|
|
||||||
|
|
||||||
auto last_block= _block_id_to_block.last();
|
|
||||||
if( last_block.valid() )
|
|
||||||
_fork_db.start_block( *last_block );
|
|
||||||
|
|
||||||
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }
|
|
||||||
|
|
||||||
void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
|
void database::reindex(fc::path data_dir, const genesis_state_type& initial_allocation)
|
||||||
{ try {
|
{ try {
|
||||||
wipe(data_dir, false);
|
wipe(data_dir, false);
|
||||||
open(data_dir, initial_allocation);
|
open(data_dir, [&initial_allocation]{return initial_allocation;});
|
||||||
|
|
||||||
auto start = fc::time_point::now();
|
auto start = fc::time_point::now();
|
||||||
auto last_block = _block_id_to_block.last();
|
auto last_block = _block_id_to_block.last();
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,19 @@ namespace graphene { namespace chain {
|
||||||
skip_assert_evaluation = 0x400 ///< used while reindexing
|
skip_assert_evaluation = 0x400 ///< used while reindexing
|
||||||
};
|
};
|
||||||
|
|
||||||
void open(const fc::path& data_dir, const genesis_state_type& initial_allocation = genesis_state_type());
|
/**
|
||||||
|
* @brief Open a database, creating a new one if necessary
|
||||||
|
*
|
||||||
|
* Opens a database in the specified directory. If no initialized database is found, genesis_loader is called
|
||||||
|
* and its return value is used as the genesis state when initializing the new database
|
||||||
|
*
|
||||||
|
* genesis_loader will not be called if an existing database is found.
|
||||||
|
*
|
||||||
|
* @param data_dir Path to open or create database in
|
||||||
|
* @param genesis_loader A callable object which returns the genesis state to initialize new databases on
|
||||||
|
*/
|
||||||
|
template<typename F>
|
||||||
|
void open(const fc::path& data_dir, F&& genesis_loader);
|
||||||
/**
|
/**
|
||||||
* @brief Rebuild object graph from block history and open detabase
|
* @brief Rebuild object graph from block history and open detabase
|
||||||
*
|
*
|
||||||
|
|
@ -477,4 +489,24 @@ namespace graphene { namespace chain {
|
||||||
(void)l;
|
(void)l;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename F>
|
||||||
|
void database::open(const fc::path& data_dir, F&& genesis_loader)
|
||||||
|
{ try {
|
||||||
|
object_database::open(data_dir);
|
||||||
|
|
||||||
|
_block_id_to_block.open(data_dir / "database" / "block_num_to_block");
|
||||||
|
|
||||||
|
if( !find(global_property_id_type()) )
|
||||||
|
init_genesis(genesis_loader());
|
||||||
|
|
||||||
|
_pending_block.previous = head_block_id();
|
||||||
|
_pending_block.timestamp = head_block_time();
|
||||||
|
|
||||||
|
auto last_block= _block_id_to_block.last();
|
||||||
|
if( last_block.valid() )
|
||||||
|
_fork_db.start_block( *last_block );
|
||||||
|
|
||||||
|
} FC_CAPTURE_AND_RETHROW( (data_dir) ) }
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ void database_fixture::open_database()
|
||||||
{
|
{
|
||||||
if( !data_dir ) {
|
if( !data_dir ) {
|
||||||
data_dir = fc::temp_directory();
|
data_dir = fc::temp_directory();
|
||||||
db.open(data_dir->path(), genesis_state);
|
db.open(data_dir->path(), [this]{return genesis_state;});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
|
||||||
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
||||||
{
|
{
|
||||||
database db;
|
database db;
|
||||||
db.open(data_dir.path(), make_genesis() );
|
db.open(data_dir.path(), make_genesis );
|
||||||
b = db.generate_block(now, db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing);
|
b = db.generate_block(now, db.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing);
|
||||||
|
|
||||||
for( uint32_t i = 1; i < 200; ++i )
|
for( uint32_t i = 1; i < 200; ++i )
|
||||||
|
|
@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE( generate_empty_blocks )
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
database db;
|
database db;
|
||||||
db.open(data_dir.path() );
|
db.open(data_dir.path(), []{return genesis_state_type();});
|
||||||
BOOST_CHECK_EQUAL( db.head_block_num(), 200 );
|
BOOST_CHECK_EQUAL( db.head_block_num(), 200 );
|
||||||
for( uint32_t i = 0; i < 200; ++i )
|
for( uint32_t i = 0; i < 200; ++i )
|
||||||
{
|
{
|
||||||
|
|
@ -171,7 +171,7 @@ BOOST_AUTO_TEST_CASE( undo_block )
|
||||||
fc::temp_directory data_dir;
|
fc::temp_directory data_dir;
|
||||||
{
|
{
|
||||||
database db;
|
database db;
|
||||||
db.open(data_dir.path(), make_genesis() );
|
db.open(data_dir.path(), make_genesis);
|
||||||
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
||||||
|
|
||||||
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
||||||
|
|
@ -211,9 +211,9 @@ BOOST_AUTO_TEST_CASE( fork_blocks )
|
||||||
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
||||||
|
|
||||||
database db1;
|
database db1;
|
||||||
db1.open(data_dir1.path(), make_genesis());
|
db1.open(data_dir1.path(), make_genesis);
|
||||||
database db2;
|
database db2;
|
||||||
db2.open(data_dir2.path(), make_genesis());
|
db2.open(data_dir2.path(), make_genesis);
|
||||||
|
|
||||||
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
||||||
for( uint32_t i = 0; i < 10; ++i )
|
for( uint32_t i = 0; i < 10; ++i )
|
||||||
|
|
@ -276,7 +276,7 @@ BOOST_AUTO_TEST_CASE( undo_pending )
|
||||||
fc::temp_directory data_dir;
|
fc::temp_directory data_dir;
|
||||||
{
|
{
|
||||||
database db;
|
database db;
|
||||||
db.open(data_dir.path(), make_genesis());
|
db.open(data_dir.path(), make_genesis);
|
||||||
|
|
||||||
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
||||||
public_key_type delegate_pub_key = delegate_priv_key.get_public_key();
|
public_key_type delegate_pub_key = delegate_priv_key.get_public_key();
|
||||||
|
|
@ -334,8 +334,8 @@ BOOST_AUTO_TEST_CASE( switch_forks_undo_create )
|
||||||
dir2;
|
dir2;
|
||||||
database db1,
|
database db1,
|
||||||
db2;
|
db2;
|
||||||
db1.open(dir1.path(), make_genesis());
|
db1.open(dir1.path(), make_genesis);
|
||||||
db2.open(dir2.path(), make_genesis());
|
db2.open(dir2.path(), make_genesis);
|
||||||
|
|
||||||
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
fc::time_point_sec now( GRAPHENE_TESTING_GENESIS_TIMESTAMP );
|
||||||
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
auto delegate_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) );
|
||||||
|
|
@ -392,8 +392,8 @@ BOOST_AUTO_TEST_CASE( duplicate_transactions )
|
||||||
dir2;
|
dir2;
|
||||||
database db1,
|
database db1,
|
||||||
db2;
|
db2;
|
||||||
db1.open(dir1.path(), make_genesis());
|
db1.open(dir1.path(), make_genesis);
|
||||||
db2.open(dir2.path(), make_genesis());
|
db2.open(dir2.path(), make_genesis);
|
||||||
|
|
||||||
auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check;
|
auto skip_sigs = database::skip_transaction_signatures | database::skip_authority_check;
|
||||||
|
|
||||||
|
|
@ -441,8 +441,8 @@ BOOST_AUTO_TEST_CASE( tapos )
|
||||||
dir2;
|
dir2;
|
||||||
database db1,
|
database db1,
|
||||||
db2;
|
db2;
|
||||||
db1.open(dir1.path(), make_genesis());
|
db1.open(dir1.path(), make_genesis);
|
||||||
db2.open(dir2.path(), make_genesis());
|
db2.open(dir2.path(), make_genesis);
|
||||||
|
|
||||||
const account_object& init1 = *db1.get_index_type<account_index>().indices().get<by_name>().find("init1");
|
const account_object& init1 = *db1.get_index_type<account_index>().indices().get<by_name>().find("init1");
|
||||||
|
|
||||||
|
|
@ -467,10 +467,6 @@ BOOST_AUTO_TEST_CASE( tapos )
|
||||||
db1.push_transaction(trx);
|
db1.push_transaction(trx);
|
||||||
now += db1.block_interval();
|
now += db1.block_interval();
|
||||||
b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing);
|
b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing);
|
||||||
/*
|
|
||||||
now += db1.block_interval();
|
|
||||||
b = db1.generate_block(now, db1.get_scheduled_witness(1).first, delegate_priv_key, database::skip_nothing);
|
|
||||||
*/
|
|
||||||
trx.clear();
|
trx.clear();
|
||||||
|
|
||||||
trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan_id, asset(50)}));
|
trx.operations.push_back(transfer_operation({asset(), account_id_type(), nathan_id, asset(50)}));
|
||||||
|
|
|
||||||
|
|
@ -1001,7 +1001,7 @@ BOOST_AUTO_TEST_CASE( balance_object_test )
|
||||||
|
|
||||||
genesis_state.initial_accounts.emplace_back("n", n_key.get_public_key());
|
genesis_state.initial_accounts.emplace_back("n", n_key.get_public_key());
|
||||||
|
|
||||||
db.open(td.path(), genesis_state);
|
db.open(td.path(), [this]{return genesis_state;});
|
||||||
const balance_object& balance = balance_id_type()(db);
|
const balance_object& balance = balance_id_type()(db);
|
||||||
BOOST_CHECK_EQUAL(balance.balance.amount.value, 1);
|
BOOST_CHECK_EQUAL(balance.balance.amount.value, 1);
|
||||||
BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1);
|
BOOST_CHECK_EQUAL(balance_id_type(1)(db).balance.amount.value, 1);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue