Electroneum
Loading...
Searching...
No Matches
blockchain_depth.cpp File Reference
#include <boost/range/adaptor/transformed.hpp>
#include <boost/algorithm/string.hpp>
#include "common/command_line.h"
#include "common/varint.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_depth.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 41 of file blockchain_depth.cpp.

Function Documentation

◆ main()

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

Definition at line 47 of file blockchain_depth.cpp.

48{
49 TRY_ENTRY();
50
52
53 std::string default_db_type = "lmdb";
54
55 std::string available_dbs = cryptonote::blockchain_db_types(", ");
56 available_dbs = "available: " + available_dbs;
57
58 uint32_t log_level = 0;
59
61
62 boost::filesystem::path output_file_path;
63
64 po::options_description desc_cmd_only("Command line options");
65 po::options_description desc_cmd_sett("Command line options and settings options");
66 const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
68 "database", available_dbs.c_str(), default_db_type
69 };
70 const command_line::arg_descriptor<std::string> arg_txid = {"txid", "Get min depth for this txid", ""};
71 const command_line::arg_descriptor<uint64_t> arg_height = {"height", "Get min depth for all txes at this height", 0};
72 const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Include coinbase in the average", false};
73
77 command_line::add_arg(desc_cmd_sett, arg_log_level);
78 command_line::add_arg(desc_cmd_sett, arg_database);
79 command_line::add_arg(desc_cmd_sett, arg_txid);
80 command_line::add_arg(desc_cmd_sett, arg_height);
81 command_line::add_arg(desc_cmd_sett, arg_include_coinbase);
83
84 po::options_description desc_options("Allowed options");
85 desc_options.add(desc_cmd_only).add(desc_cmd_sett);
86
87 po::variables_map vm;
88 bool r = command_line::handle_error_helper(desc_options, [&]()
89 {
90 auto parser = po::command_line_parser(argc, argv).options(desc_options);
91 po::store(parser.run(), vm);
92 po::notify(vm);
93 return true;
94 });
95 if (! r)
96 return 1;
97
99 {
100 std::cout << "Electroneum '" << ELECTRONEUM_RELEASE_NAME << "' (v" << ELECTRONEUM_VERSION_FULL << ")" << ENDL << ENDL;
101 std::cout << desc_options << std::endl;
102 return 1;
103 }
104
105 mlog_configure(mlog_get_default_log_path("electroneum-blockchain-depth.log"), true);
106 if (!command_line::is_arg_defaulted(vm, arg_log_level))
107 mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
108 else
109 mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
110
111 LOG_PRINT_L0("Starting...");
112
113 std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
115 bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
116 network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
117 std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
118 uint64_t opt_height = command_line::get_arg(vm, arg_height);
119 bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
120
121 if (!opt_txid_string.empty() && opt_height)
122 {
123 std::cerr << "txid and height cannot be given at the same time" << std::endl;
124 return 1;
125 }
126 crypto::hash opt_txid = crypto::null_hash;
127 if (!opt_txid_string.empty())
128 {
129 if (!epee::string_tools::hex_to_pod(opt_txid_string, opt_txid))
130 {
131 std::cerr << "Invalid txid" << std::endl;
132 return 1;
133 }
134 }
135
136 std::string db_type = command_line::get_arg(vm, arg_database);
138 {
139 std::cerr << "Invalid database type: " << db_type << std::endl;
140 return 1;
141 }
142
143 // If we wanted to use the memory pool, we would set up a fake_core.
144
145 // Use Blockchain instead of lower-level BlockchainDB for two reasons:
146 // 1. Blockchain has the init() method for easy setup
147 // 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
148 //
149 // cannot match blockchain_storage setup above with just one line,
150 // e.g.
151 // Blockchain* core_storage = new Blockchain(NULL);
152 // because unlike blockchain_storage constructor, which takes a pointer to
153 // tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
154 LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
155 std::unique_ptr<Blockchain> core_storage;
156 tx_memory_pool m_mempool(*core_storage);
157 core_storage.reset(new Blockchain(m_mempool));
158 BlockchainDB *db = new_db(db_type);
159 if (db == NULL)
160 {
161 LOG_ERROR("Attempted to use non-existent database type: " << db_type);
162 throw std::runtime_error("Attempting to use non-existent database type");
163 }
164 LOG_PRINT_L0("database: " << db_type);
165
166 const std::string filename = (boost::filesystem::path(opt_data_dir) / db->get_db_name()).string();
167 LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
168
169 try
170 {
171 db->open(filename, DBF_RDONLY);
172 }
173 catch (const std::exception& e)
174 {
175 LOG_PRINT_L0("Error opening database: " << e.what());
176 return 1;
177 }
178 r = core_storage->init(db, net_type);
179
180 CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
181 LOG_PRINT_L0("Source blockchain storage initialized OK");
182
183 std::vector<crypto::hash> start_txids;
184 if (!opt_txid_string.empty())
185 {
186 start_txids.push_back(opt_txid);
187 }
188 else
189 {
190 const cryptonote::blobdata bd = db->get_block_blob_from_height(opt_height);
193 {
194 LOG_PRINT_L0("Bad block from db");
195 return 1;
196 }
197 for (const crypto::hash &txid: b.tx_hashes)
198 start_txids.push_back(txid);
199 if (opt_include_coinbase)
200 start_txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
201 }
202
203 if (start_txids.empty())
204 {
205 LOG_PRINT_L0("No transaction(s) to check");
206 return 1;
207 }
208
209 std::vector<uint64_t> depths;
210 for (const crypto::hash &start_txid: start_txids)
211 {
212 uint64_t depth = 0;
213 bool coinbase = false;
214
215 LOG_PRINT_L0("Checking depth for txid " << start_txid);
216 std::vector<crypto::hash> txids(1, start_txid);
217 while (!coinbase)
218 {
219 LOG_PRINT_L0("Considering "<< txids.size() << " transaction(s) at depth " << depth);
220 std::vector<crypto::hash> new_txids;
221 for (const crypto::hash &txid: txids)
222 {
224 if (!db->get_pruned_tx_blob(txid, bd))
225 {
226 LOG_PRINT_L0("Failed to get txid " << txid << " from db");
227 return 1;
228 }
231 {
232 LOG_PRINT_L0("Bad tx: " << txid);
233 return 1;
234 }
235 for (size_t ring = 0; ring < tx.vin.size(); ++ring)
236 {
237 if (tx.vin[ring].type() == typeid(cryptonote::txin_gen))
238 {
239 MDEBUG(txid << " is a coinbase transaction");
240 coinbase = true;
241 goto done;
242 }
243 if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
244 {
245 const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
246 const uint64_t amount = txin.amount;
248 for (uint64_t offset: absolute_offsets)
249 {
250 const output_data_t od = db->get_output_key(amount, offset);
251 const crypto::hash block_hash = db->get_block_hash_from_height(od.height);
252 bd = db->get_block_blob(block_hash);
255 {
256 LOG_PRINT_L0("Bad block from db");
257 return 1;
258 }
259 // find the tx which created this output
260 bool found = false;
261 for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
262 {
263 if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
264 {
265 const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
266 if (txout.key == od.pubkey)
267 {
268 found = true;
269 new_txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
270 MDEBUG("adding txid: " << cryptonote::get_transaction_hash(b.miner_tx));
271 break;
272 }
273 }
274 else
275 {
276 LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
277 return 1;
278 }
279 }
280 for (const crypto::hash &block_txid: b.tx_hashes)
281 {
282 if (found)
283 break;
284 if (!db->get_pruned_tx_blob(block_txid, bd))
285 {
286 LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
287 return 1;
288 }
291 {
292 LOG_PRINT_L0("Bad tx: " << block_txid);
293 return 1;
294 }
295 for (size_t out = 0; out < tx2.vout.size(); ++out)
296 {
297 if (tx2.vout[out].target.type() == typeid(cryptonote::txout_to_key))
298 {
299 const auto &txout = boost::get<cryptonote::txout_to_key>(tx2.vout[out].target);
300 if (txout.key == od.pubkey)
301 {
302 found = true;
303 new_txids.push_back(block_txid);
304 MDEBUG("adding txid: " << block_txid);
305 break;
306 }
307 }
308 else
309 {
310 LOG_PRINT_L0("Bad vout type in txid " << block_txid);
311 return 1;
312 }
313 }
314 }
315 if (!found)
316 {
317 LOG_PRINT_L0("Output originating transaction not found");
318 return 1;
319 }
320 }
321 }
322 else
323 {
324 LOG_PRINT_L0("Bad vin type in txid " << txid);
325 return 1;
326 }
327 }
328 }
329 if (!coinbase)
330 {
331 std::swap(txids, new_txids);
332 ++depth;
333 }
334 }
335done:
336 LOG_PRINT_L0("Min depth for txid " << start_txid << ": " << depth);
337 depths.push_back(depth);
338 }
339
340 uint64_t cumulative_depth = 0;
341 for (uint64_t depth: depths)
342 cumulative_depth += depth;
343 LOG_PRINT_L0("Average min depth for " << start_txids.size() << " transaction(s): " << cumulative_depth/(float)depths.size());
344 LOG_PRINT_L0("Median min depth for " << start_txids.size() << " transaction(s): " << epee::misc_utils::median(depths));
345
346 core_storage->deinit();
347 return 0;
348
349 CATCH_ENTRY("Depth query error", 1);
350}
#define DBF_RDONLY
The BlockchainDB backing store interface declaration/contract.
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t &height) const =0
fetch a block blob by height
virtual std::string get_db_name() const =0
gets the name of the folder the BlockchainDB's file(s) should be in
virtual cryptonote::blobdata get_block_blob(const crypto::hash &h) const =0
fetches the block with the given hash
virtual bool get_pruned_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const =0
fetches the pruned transaction blob with the given hash
virtual output_data_t get_output_key(const uint64_t &amount, const uint64_t &index, bool include_commitmemt=true) const =0
get some of an output's data
virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const =0
fetch a block's hash
virtual void open(const std::string &filename, const int db_flags=0)=0
open a db, or create it if necessary.
Transaction pool, handles transactions which are not part of a block.
Definition tx_pool.h:95
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 CATCH_ENTRY(location, return_val)
std::string mlog_get_default_log_path(const char *default_filename)
Definition mlog.cpp:72
#define MDEBUG(x)
Definition misc_log_ex.h:76
void mlog_set_log(const char *log)
Definition mlog.cpp:288
#define ENDL
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define TRY_ENTRY()
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99
void add_arg(boost::program_options::options_description &description, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg, bool unique=true)
const arg_descriptor< bool > arg_help
bool is_arg_defaulted(const boost::program_options::variables_map &vm, const arg_descriptor< T, required, dependent, NUM_DEPS > &arg)
bool handle_error_helper(const boost::program_options::options_description &desc, F parser)
T get_arg(const boost::program_options::variables_map &vm, const arg_descriptor< T, false, true > &arg)
POD_CLASS hash
Definition hash.h:50
const command_line::arg_descriptor< std::string, false, true, 2 > arg_data_dir
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
const command_line::arg_descriptor< bool, false > arg_testnet_on
BlockchainDB * new_db(const std::string &db_type)
crypto::hash get_transaction_hash(const transaction &t)
bool blockchain_valid_db_type(const std::string &db_type)
const command_line::arg_descriptor< bool, false > arg_stagenet_on
std::string blobdata
std::string blockchain_db_types(const std::string &sep)
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
const command_line::arg_descriptor< std::string > arg_log_level
type_vec_type median(std::vector< type_vec_type > &v)
bool set_module_name_and_folder(const std::string &path_to_process_)
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
bool on_startup()
Definition util.cpp:778
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
std::vector< crypto::hash > tx_hashes
a struct containing output metadata
uint64_t height
the height of the block which created the output
crypto::public_key pubkey
the output's public key (for spend verification)
std::vector< uint64_t > key_offsets
const char *const ELECTRONEUM_RELEASE_NAME
const char *const ELECTRONEUM_VERSION_FULL
Here is the call graph for this function: