Electroneum
blockchain_prune.cpp File Reference
#include <array>
#include <lmdb.h>
#include <boost/algorithm/string.hpp>
#include "common/command_line.h"
#include "common/pruning.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_core/blockchain.h"
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/lmdb/db_lmdb.h"
#include "blockchain_db/db_types.h"
#include "version.h"
Include dependency graph for blockchain_prune.cpp:

Go to the source code of this file.

Macros

#define ELECTRONEUM_DEFAULT_LOG_CATEGORY   "bcutil"
 
#define MDB_val_set(var, val)   MDB_val var = {sizeof(val), (void *)&val}
 

Functions

int main (int argc, char *argv[])
 

Macro Definition Documentation

◆ ELECTRONEUM_DEFAULT_LOG_CATEGORY

#define ELECTRONEUM_DEFAULT_LOG_CATEGORY   "bcutil"

Definition at line 42 of file blockchain_prune.cpp.

◆ MDB_val_set

#define MDB_val_set (   var,
  val 
)    MDB_val var = {sizeof(val), (void *)&val}

Definition at line 44 of file blockchain_prune.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 438 of file blockchain_prune.cpp.

439 {
440  TRY_ENTRY();
441 
443 
444  std::string default_db_type = "lmdb";
445 
446  std::string available_dbs = cryptonote::blockchain_db_types(", ");
447  available_dbs = "available: " + available_dbs;
448 
449  uint32_t log_level = 0;
450 
452 
453  boost::filesystem::path output_file_path;
454 
455  po::options_description desc_cmd_only("Command line options");
456  po::options_description desc_cmd_sett("Command line options and settings options");
457  const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
458  const command_line::arg_descriptor<std::string> arg_database = {
459  "database", available_dbs.c_str(), default_db_type
460  };
462  "db-sync-mode"
463  , "Specify sync option, using format [safe|fast|fastest]:[nrecords_per_sync]."
464  , "fast:1000"
465  };
466  const command_line::arg_descriptor<bool> arg_copy_pruned_database = {"copy-pruned-database", "Copy database anyway if already pruned"};
467 
471  command_line::add_arg(desc_cmd_sett, arg_log_level);
472  command_line::add_arg(desc_cmd_sett, arg_database);
473  command_line::add_arg(desc_cmd_sett, arg_db_sync_mode);
474  command_line::add_arg(desc_cmd_sett, arg_copy_pruned_database);
476 
477  po::options_description desc_options("Allowed options");
478  desc_options.add(desc_cmd_only).add(desc_cmd_sett);
479 
480  po::variables_map vm;
481  bool r = command_line::handle_error_helper(desc_options, [&]()
482  {
483  auto parser = po::command_line_parser(argc, argv).options(desc_options);
484  po::store(parser.run(), vm);
485  po::notify(vm);
486  return true;
487  });
488  if (! r)
489  return 1;
490 
492  {
493  std::cout << "Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")" << ENDL << ENDL;
494  std::cout << desc_options << std::endl;
495  return 1;
496  }
497 
498  mlog_configure(mlog_get_default_log_path("electroneum-blockchain-prune.log"), true);
501  else
502  mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
503 
504  MINFO("Starting...");
505 
506  bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
507  bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
508  network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
509  bool opt_copy_pruned_database = command_line::get_arg(vm, arg_copy_pruned_database);
511  while (boost::ends_with(data_dir, "/") || boost::ends_with(data_dir, "\\"))
512  data_dir.pop_back();
513 
514  std::string db_type = command_line::get_arg(vm, arg_database);
516  {
517  MERROR("Invalid database type: " << db_type);
518  return 1;
519  }
520  if (db_type != "lmdb")
521  {
522  MERROR("Unsupported database type: " << db_type << ". Only lmdb is supported");
523  return 1;
524  }
525 
527  uint64_t db_flags = 0;
528  if (!parse_db_sync_mode(db_sync_mode, db_flags))
529  {
530  MERROR("Invalid db sync mode: " << db_sync_mode);
531  return 1;
532  }
533 
534  // If we wanted to use the memory pool, we would set up a fake_core.
535 
536  // Use Blockchain instead of lower-level BlockchainDB for two reasons:
537  // 1. Blockchain has the init() method for easy setup
538  // 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
539  //
540  // cannot match blockchain_storage setup above with just one line,
541  // e.g.
542  // Blockchain* core_storage = new Blockchain(NULL);
543  // because unlike blockchain_storage constructor, which takes a pointer to
544  // tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
545  MINFO("Initializing source blockchain (BlockchainDB)");
546  std::array<std::unique_ptr<Blockchain>, 2> core_storage;
547  Blockchain *blockchain = NULL;
548  tx_memory_pool m_mempool(*blockchain);
549  boost::filesystem::path paths[2];
550  bool already_pruned = false;
551  for (size_t n = 0; n < core_storage.size(); ++n)
552  {
553  core_storage[n].reset(new Blockchain(m_mempool));
554 
555  BlockchainDB* db = new_db(db_type);
556  if (db == NULL)
557  {
558  MERROR("Attempted to use non-existent database type: " << db_type);
559  throw std::runtime_error("Attempting to use non-existent database type");
560  }
561  MDEBUG("database: " << db_type);
562 
563  if (n == 1)
564  {
565  paths[1] = boost::filesystem::path(data_dir) / (db->get_db_name() + "-pruned");
566  if (boost::filesystem::exists(paths[1]))
567  {
568  if (!boost::filesystem::is_directory(paths[1]))
569  {
570  MERROR("LMDB needs a directory path, but a file was passed: " << paths[1].string());
571  return 1;
572  }
573  }
574  else
575  {
576  if (!boost::filesystem::create_directories(paths[1]))
577  {
578  MERROR("Failed to create directory: " << paths[1].string());
579  return 1;
580  }
581  }
582  db_path = paths[1].string();
583  }
584  else
585  {
586  paths[0] = boost::filesystem::path(data_dir) / db->get_db_name();
587  }
588 
589  MINFO("Loading blockchain from folder " << paths[n] << " ...");
590 
591  try
592  {
593  db->open(paths[n].string(), n == 0 ? DBF_RDONLY : 0);
594  }
595  catch (const std::exception& e)
596  {
597  MERROR("Error opening database: " << e.what());
598  return 1;
599  }
600  r = core_storage[n]->init(db, net_type);
601 
602  std::string source_dest = n == 0 ? "source" : "pruned";
603  CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize " << source_dest << " blockchain storage");
604  MINFO(source_dest << " blockchain storage initialized OK");
605  if (n == 0 && core_storage[0]->get_blockchain_pruning_seed())
606  {
607  if (!opt_copy_pruned_database)
608  {
609  MERROR("Blockchain is already pruned, use --" << arg_copy_pruned_database.name << " to copy it anyway");
610  return 1;
611  }
612  already_pruned = true;
613  }
614  }
615  core_storage[0]->deinit();
616  core_storage[0].reset(NULL);
617  core_storage[1]->deinit();
618  core_storage[1].reset(NULL);
619 
620  MINFO("Pruning...");
621  MDB_env *env0 = NULL, *env1 = NULL;
622  open(env0, paths[0], db_flags, true);
623  open(env1, paths[1], db_flags, false);
624  copy_table(env0, env1, "blocks", MDB_INTEGERKEY, MDB_APPEND);
625  copy_table(env0, env1, "block_info", MDB_INTEGERKEY | MDB_DUPSORT| MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
626  copy_table(env0, env1, "block_heights", MDB_INTEGERKEY | MDB_DUPSORT| MDB_DUPFIXED, 0, BlockchainLMDB::compare_hash32);
627  //copy_table(env0, env1, "txs", MDB_INTEGERKEY);
628  copy_table(env0, env1, "txs_pruned", MDB_INTEGERKEY, MDB_APPEND);
629  copy_table(env0, env1, "txs_prunable_hash", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPEND);
630  // not copied: prunable, prunable_tip
631  copy_table(env0, env1, "tx_indices", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_hash32);
632  copy_table(env0, env1, "tx_outputs", MDB_INTEGERKEY, MDB_APPEND);
633  copy_table(env0, env1, "output_txs", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
634  copy_table(env0, env1, "output_amounts", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
635  copy_table(env0, env1, "spent_keys", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
636  copy_table(env0, env1, "txpool_meta", 0, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
637  copy_table(env0, env1, "txpool_blob", 0, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
638  copy_table(env0, env1, "hf_versions", MDB_INTEGERKEY, MDB_APPEND);
639  copy_table(env0, env1, "properties", 0, 0, BlockchainLMDB::compare_string);
640  if (already_pruned)
641  {
642  copy_table(env0, env1, "txs_prunable", MDB_INTEGERKEY, MDB_APPEND, BlockchainLMDB::compare_uint64);
643  copy_table(env0, env1, "txs_prunable_tip", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_NODUPDATA, BlockchainLMDB::compare_uint64);
644  }
645  else
646  {
647  prune(env0, env1);
648  }
649  close(env1);
650  close(env0);
651 
652  MINFO("Swapping databases, pre-pruning blockchain will be left in " << paths[0].string() + "-old and can be removed if desired");
653  if (replace_file(paths[0].string(), paths[0].string() + "-old") || replace_file(paths[1].string(), paths[0].string()))
654  {
655  MERROR("Blockchain pruned OK, but renaming failed");
656  return 1;
657  }
658 
659  MINFO("Blockchain pruned OK");
660  return 0;
661 
662  CATCH_ENTRY("Pruning error", 1);
663 }
const char *const ELECTRONEUM_RELEASE_NAME
#define MERROR(x)
Definition: misc_log_ex.h:73
virtual std::string get_db_name() const =0
gets the name of the folder the BlockchainDB&#39;s file(s) should be in
#define DBF_RDONLY
#define MINFO(x)
Definition: misc_log_ex.h:75
#define MDB_NODUPDATA
Definition: lmdb.h:369
bool set_module_name_and_folder(const std::string &path_to_process_)
Definition: string_tools.h:249
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
void mlog_set_log(const char *log)
Definition: mlog.cpp:288
#define CATCH_ENTRY(location, return_val)
Definition: misc_log_ex.h:152
std::string mlog_get_default_log_path(const char *default_filename)
Definition: mlog.cpp:72
void mlog_configure(const std::string &filename_base, bool console, const std::size_t max_log_file_size=MAX_LOG_FILE_SIZE, const std::size_t max_log_files=MAX_LOG_FILES)
Definition: mlog.cpp:148
const command_line::arg_descriptor< std::string > arg_db_sync_mode
const command_line::arg_descriptor< bool, false > arg_stagenet_on
const arg_descriptor< bool > arg_help
std::string blockchain_db_types(const std::string &sep)
struct MDB_env MDB_env
Opaque structure for a database environment.
Definition: lmdb.h:260
boost::filesystem::path data_dir
Definition: main.cpp:50
virtual void open(const std::string &filename, const int db_flags=0)=0
open a db, or create it if necessary.
#define MDEBUG(x)
Definition: misc_log_ex.h:76
bool on_startup()
Definition: util.cpp:778
const char *const ELECTRONEUM_VERSION_FULL
bool blockchain_valid_db_type(const std::string &db_type)
const command_line::arg_descriptor< bool, false > arg_testnet_on
BlockchainDB * new_db(const std::string &db_type)
bool handle_error_helper(const boost::program_options::options_description &desc, F parser)
Definition: command_line.h:237
#define TRY_ENTRY()
Definition: misc_log_ex.h:151
unsigned int uint32_t
Definition: stdint.h:126
const command_line::arg_descriptor< std::string > arg_log_level
unsigned __int64 uint64_t
Definition: stdint.h:136
const command_line::arg_descriptor< std::string, false, true, 2 > arg_data_dir
#define MDB_INTEGERKEY
Definition: lmdb.h:349
#define MDB_DUPFIXED
Definition: lmdb.h:351
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
Definition: command_line.h:188
Transaction pool, handles transactions which are not part of a block.
Definition: tx_pool.h:94
#define MDB_APPEND
Definition: lmdb.h:377
The BlockchainDB backing store interface declaration/contract.
#define ENDL
Definition: misc_log_ex.h:149
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
Definition: command_line.h:271
std::string to_string(t_connection_type type)
#define MDB_DUPSORT
Definition: lmdb.h:345
int compare_uint64(const MDB_val *a, const MDB_val *b)
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
Definition: command_line.h:265
#define MDB_APPENDDUP
Definition: lmdb.h:379
Here is the call graph for this function: