@ -38,52 +38,179 @@
# include "cryptonote_core/blockchain.h"
# include "blockchain_db/lmdb/db_lmdb.h"
# include "cryptonote_core/tx_pool.h"
# include "common/command_line.h"
# include "serialization/json_utils.h"
# include "include_base_utils.h"
# include "version.h"
# include <iostream>
// CONFIG
static bool opt_batch = true ;
static bool opt_testnet = false ;
// number of blocks per batch transaction
// adjustable through command-line argument according to available RAM
static uint64_t db_batch_size = 20000 ;
namespace po = boost : : program_options ;
using namespace cryptonote ;
using namespace epee ;
struct fake_core
{
tx_memory_pool m_pool ;
Blockchain dummy ;
tx_memory_pool m_pool ;
blockchain_storage m_storage ;
fake_core ( const boost : : filesystem : : path & path ) : m_pool ( dummy ) , dummy ( m_pool ) , m_storage ( & m_pool )
# if !defined(BLOCKCHAIN_DB)
// for multi_db_runtime:
fake_core ( const boost : : filesystem : : path & path , const bool use_testnet ) : dummy ( m_pool ) , m_pool ( & dummy ) , m_storage ( m_pool )
# else
// for multi_db_compile:
fake_core ( const boost : : filesystem : : path & path , const bool use_testnet ) : dummy ( m_pool ) , m_pool ( dummy ) , m_storage ( & m_pool )
# endif
{
m_pool . init ( path . string ( ) ) ;
m_storage . init ( path . string ( ) , false ) ;
m_storage . init ( path . string ( ) , use_testnet ) ;
}
} ;
int main ( int argc , char * argv [ ] )
{
std : : string dir = tools : : get_default_data_dir ( ) ;
boost : : filesystem : : path default_data_path { dir } ;
if ( argc > = 2 & & ! strcmp ( argv [ 1 ] , " --testnet " ) ) {
default_data_path / = " testnet " ;
uint64_t height = 0 ;
uint64_t start_block = 0 ;
uint64_t end_block = 0 ;
uint64_t num_blocks = 0 ;
boost : : filesystem : : path default_data_path { tools : : get_default_data_dir ( ) } ;
boost : : filesystem : : path default_testnet_data_path { default_data_path / " testnet " } ;
po : : options_description desc_cmd_only ( " Command line options " ) ;
po : : options_description desc_cmd_sett ( " Command line options and settings options " ) ;
const command_line : : arg_descriptor < uint32_t > arg_log_level = { " log-level " , " " , LOG_LEVEL_0 } ;
const command_line : : arg_descriptor < uint64_t > arg_batch_size = { " batch-size " , " " , db_batch_size } ;
const command_line : : arg_descriptor < bool > arg_testnet_on = {
" testnet "
, " Run on testnet. "
, opt_testnet
} ;
const command_line : : arg_descriptor < uint64_t > arg_block_number =
{ " block-number " , " Number of blocks (default: use entire source blockchain) " ,
0 } ;
command_line : : add_arg ( desc_cmd_sett , command_line : : arg_data_dir , default_data_path . string ( ) ) ;
command_line : : add_arg ( desc_cmd_sett , command_line : : arg_testnet_data_dir , default_testnet_data_path . string ( ) ) ;
command_line : : add_arg ( desc_cmd_sett , arg_log_level ) ;
command_line : : add_arg ( desc_cmd_sett , arg_batch_size ) ;
command_line : : add_arg ( desc_cmd_sett , arg_testnet_on ) ;
command_line : : add_arg ( desc_cmd_sett , arg_block_number ) ;
command_line : : add_arg ( desc_cmd_only , command_line : : arg_help ) ;
const command_line : : arg_descriptor < bool > arg_batch = { " batch " ,
" Batch transactions for faster import " , true } ;
// call add_options() directly for these arguments since command_line helpers
// support only boolean switch, not boolean argument
desc_cmd_sett . add_options ( )
( arg_batch . name , make_semantic ( arg_batch ) , arg_batch . description )
;
po : : options_description desc_options ( " Allowed options " ) ;
desc_options . add ( desc_cmd_only ) . add ( desc_cmd_sett ) ;
po : : variables_map vm ;
bool r = command_line : : handle_error_helper ( desc_options , [ & ] ( )
{
po : : store ( po : : parse_command_line ( argc , argv , desc_options ) , vm ) ;
po : : notify ( vm ) ;
return true ;
} ) ;
if ( ! r )
return 1 ;
int log_level = command_line : : get_arg ( vm , arg_log_level ) ;
opt_batch = command_line : : get_arg ( vm , arg_batch ) ;
db_batch_size = command_line : : get_arg ( vm , arg_batch_size ) ;
if ( command_line : : get_arg ( vm , command_line : : arg_help ) )
{
std : : cout < < CRYPTONOTE_NAME < < " v " < < MONERO_VERSION_FULL < < ENDL < < ENDL ;
std : : cout < < desc_options < < std : : endl ;
return 1 ;
}
fake_core c ( default_data_path ) ;
if ( ! opt_batch & & ! vm [ " batch-size " ] . defaulted ( ) )
{
std : : cerr < < " Error: batch-size set, but batch option not enabled " < < ENDL ;
return 1 ;
}
if ( ! db_batch_size )
{
std : : cerr < < " Error: batch-size must be > 0 " < < ENDL ;
return 1 ;
}
BlockchainDB * blockchain ;
log_space : : get_set_log_detalisation_level ( true , log_level ) ;
log_space : : log_singletone : : add_logger ( LOGGER_CONSOLE , NULL , NULL ) ;
LOG_PRINT_L0 ( " Starting... " ) ;
blockchain = new BlockchainLMDB ( ) ;
std : : string src_folder ;
opt_testnet = command_line : : get_arg ( vm , arg_testnet_on ) ;
auto data_dir_arg = opt_testnet ? command_line : : arg_testnet_data_dir : command_line : : arg_data_dir ;
src_folder = command_line : : get_arg ( vm , data_dir_arg ) ;
boost : : filesystem : : path dest_folder ( src_folder ) ;
boost : : filesystem : : path db_path ( default_data_path ) ;
num_blocks = command_line : : get_arg ( vm , arg_block_number ) ;
db_path / = blockchain - > get_db_name ( ) ;
if ( opt_batch )
{
LOG_PRINT_L0 ( " batch: " < < std : : boolalpha < < opt_batch < < std : : noboolalpha
< < " batch size: " < < db_batch_size ) ;
}
else
{
LOG_PRINT_L0 ( " batch: " < < std : : boolalpha < < opt_batch < < std : : noboolalpha ) ;
}
LOG_PRINT_L0 ( " testnet: " < < std : : boolalpha < < opt_testnet < < std : : noboolalpha ) ;
fake_core c ( src_folder , opt_testnet ) ;
blockchain - > open ( db_path . string ( ) ) ;
height = c . m_storage . get_current_blockchain_height ( ) ;
if ( ! num_blocks | | num_blocks > height )
end_block = height - 1 ;
else
end_block = start_block + num_blocks - 1 ;
BlockchainDB * blockchain ;
blockchain = new BlockchainLMDB ( opt_batch ) ;
dest_folder / = blockchain - > get_db_name ( ) ;
LOG_PRINT_L0 ( " Source blockchain: " < < src_folder ) ;
LOG_PRINT_L0 ( " Dest blockchain: " < < dest_folder . string ( ) ) ;
LOG_PRINT_L0 ( " Opening LMDB: " < < dest_folder . string ( ) ) ;
blockchain - > open ( dest_folder . string ( ) ) ;
for ( uint64_t height , i = 0 ; i < ( height = c . m_storage . get_current_blockchain_height ( ) ) ; + + i )
if ( opt_batch )
blockchain - > batch_start ( ) ;
uint64_t i = 0 ;
for ( i = start_block ; i < end_block + 1 ; + + i )
{
if ( i % 10 = = 0 )
// block: i height: i+1 end height: end_block + 1
if ( ( i + 1 ) % 10 = = 0 )
{
std : : cout < < " \r \r " < < " block " < < i < < " / " < < height
< < " ( " < < ( i + 1 ) * 100 / height < < " %) " < < std : : flush ;
std : : cout < < " \r \r " < < " height " < < i + 1 < < " / " < <
end_block + 1 < < " ( " < < ( i + 1 ) * 100 / ( end_block + 1 ) < < " %) " < < std : : flush ;
}
// for debugging:
// std::cout << "height " << i+1 << "/" << end_block+1
// << " ((" << i+1 << ")*100/(end_block+1))" << "%)" << ENDL;
block b = c . m_storage . get_block ( i ) ;
size_t bsize = c . m_storage . get_block_size ( i ) ;
difficulty_type bdiff = c . m_storage . get_block_cumulative_difficulty ( i ) ;
@ -94,8 +221,8 @@ int main(int argc, char* argv[])
c . m_storage . get_transactions ( b . tx_hashes , txs , missed ) ;
if ( missed . size ( ) )
{
std : : cout < < std: : endl ;
std : : cerr < < " Missed transaction(s) for block at height " < < i << " , exiting " < < std: : endl ;
std : : cout < < ENDL ;
std : : cerr < < " Missed transaction(s) for block at height " < < i + 1 << " , exiting " < < ENDL ;
delete blockchain ;
return 1 ;
}
@ -103,17 +230,40 @@ int main(int argc, char* argv[])
try
{
blockchain - > add_block ( b , bsize , bdiff , bcoins , txs ) ;
if ( opt_batch )
{
if ( ( i < end_block ) & & ( ( i + 1 ) % db_batch_size = = 0 ) )
{
std : : cout < < " \r \r " ;
std : : cout < < " [- batch commit at height " < < i + 1 < < " -] " < < ENDL ;
blockchain - > batch_stop ( ) ;
blockchain - > batch_start ( ) ;
std : : cout < < ENDL ;
blockchain - > show_stats ( ) ;
}
}
}
catch ( const std : : exception & e )
{
std : : cout < < std : : endl ;
std : : cerr < < " Error adding block to new blockchain: " < < e . what ( ) < < std : : endl ;
std : : cout < < ENDL ;
std : : cerr < < " Error adding block to new blockchain: " < < e . what ( ) < < ENDL ;
delete blockchain ;
return 2 ;
}
}
if ( opt_batch )
{
std : : cout < < " \r \r " < < " height " < < i < < " / " < <
end_block + 1 < < " ( " < < ( i ) * 100 / ( end_block + 1 ) < < " %) " < < std : : flush ;
std : : cout < < ENDL ;
std : : cout < < " [- batch commit at height " < < i < < " -] " < < ENDL ;
blockchain - > batch_stop ( ) ;
}
std : : cout < < ENDL ;
blockchain - > show_stats ( ) ;
std : : cout < < " Finished at height: " < < i < < " block: " < < i - 1 < < ENDL ;
std : : cout < < std : : endl ;
delete blockchain ;
return 0 ;
}