Electroneum
blockchain_prune_known_spent_data.cpp File Reference
#include <boost/algorithm/string.hpp>
#include "common/command_line.h"
#include "serialization/crypto.h"
#include "cryptonote_core/tx_pool.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_core/blockchain.h"
#include "blockchain_db/blockchain_db.h"
#include "blockchain_db/db_types.h"
#include "version.h"
Include dependency graph for blockchain_prune_known_spent_data.cpp:

Go to the source code of this file.

Macros

#define ELECTRONEUM_DEFAULT_LOG_CATEGORY   "bcutil"
 

Functions

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

Macro Definition Documentation

◆ ELECTRONEUM_DEFAULT_LOG_CATEGORY

#define ELECTRONEUM_DEFAULT_LOG_CATEGORY   "bcutil"

Definition at line 40 of file blockchain_prune_known_spent_data.cpp.

Function Documentation

◆ main()

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

Definition at line 99 of file blockchain_prune_known_spent_data.cpp.

100 {
101  TRY_ENTRY();
102 
104 
105  std::string default_db_type = "lmdb";
106 
107  std::string available_dbs = cryptonote::blockchain_db_types(", ");
108  available_dbs = "available: " + available_dbs;
109 
110  uint32_t log_level = 0;
111 
113 
114  po::options_description desc_cmd_only("Command line options");
115  po::options_description desc_cmd_sett("Command line options and settings options");
116  const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
117  const command_line::arg_descriptor<std::string> arg_database = {
118  "database", available_dbs.c_str(), default_db_type
119  };
120  const command_line::arg_descriptor<bool> arg_verbose = {"verbose", "Verbose output", false};
121  const command_line::arg_descriptor<bool> arg_dry_run = {"dry-run", "Do not actually prune", false};
122  const command_line::arg_descriptor<std::string> arg_input = {"input", "Path to the known spent outputs file"};
123 
127  command_line::add_arg(desc_cmd_sett, arg_log_level);
128  command_line::add_arg(desc_cmd_sett, arg_database);
129  command_line::add_arg(desc_cmd_sett, arg_verbose);
130  command_line::add_arg(desc_cmd_sett, arg_dry_run);
131  command_line::add_arg(desc_cmd_sett, arg_input);
133 
134  po::options_description desc_options("Allowed options");
135  desc_options.add(desc_cmd_only).add(desc_cmd_sett);
136 
137  po::variables_map vm;
138  bool r = command_line::handle_error_helper(desc_options, [&]()
139  {
140  auto parser = po::command_line_parser(argc, argv).options(desc_options);
141  po::store(parser.run(), vm);
142  po::notify(vm);
143  return true;
144  });
145  if (! r)
146  return 1;
147 
149  {
150  std::cout << "Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")" << ENDL << ENDL;
151  std::cout << desc_options << std::endl;
152  return 1;
153  }
154 
155  mlog_configure(mlog_get_default_log_path("electroneum-blockchain-prune-known-spent-data.log"), true);
158  else
159  mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
160 
161  LOG_PRINT_L0("Starting...");
162 
164  bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
165  bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
166  network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
167  bool opt_verbose = command_line::get_arg(vm, arg_verbose);
168  bool opt_dry_run = command_line::get_arg(vm, arg_dry_run);
169 
170  std::string db_type = command_line::get_arg(vm, arg_database);
172  {
173  std::cerr << "Invalid database type: " << db_type << std::endl;
174  return 1;
175  }
176 
177  const std::string input = command_line::get_arg(vm, arg_input);
178 
179  LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
180  std::unique_ptr<Blockchain> core_storage;
181  tx_memory_pool m_mempool(*core_storage);
182  core_storage.reset(new Blockchain(m_mempool));
183  BlockchainDB *db = new_db(db_type);
184  if (db == NULL)
185  {
186  LOG_ERROR("Attempted to use non-existent database type: " << db_type);
187  throw std::runtime_error("Attempting to use non-existent database type");
188  }
189  LOG_PRINT_L0("database: " << db_type);
190 
191  const std::string filename = (boost::filesystem::path(opt_data_dir) / db->get_db_name()).string();
192  LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
193 
194  try
195  {
196  db->open(filename, 0);
197  }
198  catch (const std::exception& e)
199  {
200  LOG_PRINT_L0("Error opening database: " << e.what());
201  return 1;
202  }
203  r = core_storage->init(db, net_type);
204 
205  CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
206  LOG_PRINT_L0("Source blockchain storage initialized OK");
207 
208  std::map<uint64_t, uint64_t> known_spent_outputs;
209  if (input.empty())
210  {
211  std::map<uint64_t, std::pair<uint64_t, uint64_t>> outputs;
212 
213  LOG_PRINT_L0("Scanning for known spent data...");
214  db->for_all_transactions([&](const crypto::hash &txid, const cryptonote::transaction &tx){
215  const bool miner_tx = tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen);
216  for (const auto &in: tx.vin)
217  {
218  if (in.type() != typeid(txin_to_key))
219  continue;
220  const auto &txin = boost::get<txin_to_key>(in);
221  if (txin.amount == 0)
222  continue;
223 
224  outputs[txin.amount].second++;
225  }
226 
227  for (const auto &out: tx.vout)
228  {
229  uint64_t amount = out.amount;
230  if (out.target.type() != typeid(txout_to_key))
231  continue;
232 
233  outputs[amount].first++;
234  }
235  return true;
236  }, true);
237 
238  for (const auto &i: outputs)
239  {
240  known_spent_outputs[i.first] = i.second.second;
241  }
242  }
243  else
244  {
245  LOG_PRINT_L0("Loading known spent data...");
246  known_spent_outputs = load_outputs(input);
247  }
248 
249  LOG_PRINT_L0("Pruning known spent data...");
250 
251  bool stop_requested = false;
252  tools::signal_handler::install([&stop_requested](int type) {
253  stop_requested = true;
254  });
255 
256  db->batch_start();
257 
258  size_t num_total_outputs = 0, num_prunable_outputs = 0, num_known_spent_outputs = 0, num_eligible_outputs = 0, num_eligible_known_spent_outputs = 0;
259  for (auto i = known_spent_outputs.begin(); i != known_spent_outputs.end(); ++i)
260  {
261  uint64_t num_outputs = db->get_num_outputs(i->first);
262  num_total_outputs += num_outputs;
263  num_known_spent_outputs += i->second;
264  if (i->first == 0 || is_valid_decomposed_amount(i->first))
265  {
266  if (opt_verbose)
267  MINFO("Ignoring output value " << i->first << ", with " << num_outputs << " outputs");
268  continue;
269  }
270  num_eligible_outputs += num_outputs;
271  num_eligible_known_spent_outputs += i->second;
272  if (opt_verbose)
273  MINFO(i->first << ": " << i->second << "/" << num_outputs);
274  if (num_outputs > i->second)
275  continue;
276  if (num_outputs && num_outputs < i->second)
277  {
278  MERROR("More outputs are spent than known for amount " << i->first << ", not touching");
279  continue;
280  }
281  if (opt_verbose)
282  MINFO("Pruning data for " << num_outputs << " outputs");
283  if (!opt_dry_run)
284  db->prune_outputs(i->first);
285  num_prunable_outputs += i->second;
286  }
287 
288  db->batch_stop();
289 
290  MINFO("Total outputs: " << num_total_outputs);
291  MINFO("Known spent outputs: " << num_known_spent_outputs);
292  MINFO("Eligible outputs: " << num_eligible_outputs);
293  MINFO("Eligible known spent outputs: " << num_eligible_known_spent_outputs);
294  MINFO("Prunable outputs: " << num_prunable_outputs);
295 
296  LOG_PRINT_L0("Blockchain known spent data pruned OK");
297  core_storage->deinit();
298  return 0;
299 
300  CATCH_ENTRY("Error", 1);
301 }
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 MINFO(x)
Definition: misc_log_ex.h:75
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
#define LOG_PRINT_L0(x)
Definition: misc_log_ex.h:99
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)
virtual bool for_all_transactions(std::function< bool(const crypto::hash &, const cryptonote::transaction &)>, bool pruned) const =0
runs a function over all transactions stored
virtual uint64_t get_num_outputs(const uint64_t &amount) const =0
fetches the number of outputs of a given amount
virtual void open(const std::string &filename, const int db_flags=0)=0
open a db, or create it if necessary.
bool on_startup()
Definition: util.cpp:778
const char *const ELECTRONEUM_VERSION_FULL
bool blockchain_valid_db_type(const std::string &db_type)
bool is_valid_decomposed_amount(uint64_t amount)
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
virtual void prune_outputs(uint64_t amount)=0
prune output data for the given amount
unsigned __int64 uint64_t
Definition: stdint.h:136
const command_line::arg_descriptor< std::string, false, true, 2 > arg_data_dir
virtual void batch_stop()=0
ends a batch transaction
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
static bool install(T t)
installs a signal handler
Definition: util.h:164
Transaction pool, handles transactions which are not part of a block.
Definition: tx_pool.h:94
The BlockchainDB backing store interface declaration/contract.
#define LOG_ERROR(x)
Definition: misc_log_ex.h:98
#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
bool init(BlockchainDB *db, const network_type nettype=MAINNET, bool offline=false, const cryptonote::test_options *test_options=NULL, difficulty_type fixed_difficulty=0, const GetCheckpointsCallback &get_checkpoints=nullptr, bool ignore_bsig=false, bool fallback_to_pow=false)
Initialize the Blockchain state.
Definition: blockchain.cpp:334
POD_CLASS hash
Definition: hash.h:50
std::string to_string(t_connection_type type)
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
bool deinit()
Uninitializes the blockchain state.
Definition: blockchain.cpp:660
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0)=0
tells the BlockchainDB to start a new "batch" of blocks
Here is the call graph for this function: