Electroneum
Loading...
Searching...
No Matches
BootstrapFile Class Reference

#include <bootstrap_file.h>

Collaboration diagram for BootstrapFile:

Public Member Functions

uint64_t count_bytes (std::ifstream &import_file, uint64_t blocks, uint64_t &h, bool &quit)
uint64_t count_blocks (const std::string &dir_path, std::streampos &start_pos, uint64_t &seek_height)
uint64_t count_blocks (const std::string &dir_path)
uint64_t seek_to_first_chunk (std::ifstream &import_file, uint8_t &major_version, uint8_t &minor_version)
bool store_blockchain_raw (cryptonote::Blockchain *cs, cryptonote::tx_memory_pool *txp, boost::filesystem::path &output_file, uint64_t use_block_height=0)

Protected Types

typedef std::vector< char > buffer_type

Protected Member Functions

bool open_writer (const boost::filesystem::path &file_path)
bool initialize_file ()
bool close ()
void write_block (block &block)
void flush_chunk ()

Protected Attributes

Blockchainm_blockchain_storage
tx_memory_poolm_tx_pool
std::ofstream * m_raw_data_file
buffer_type m_buffer
boost::iostreams::stream< boost::iostreams::back_insert_device< buffer_type > > * m_output_stream

Detailed Description

Definition at line 56 of file bootstrap_file.h.

Member Typedef Documentation

◆ buffer_type

typedef std::vector<char> BootstrapFile::buffer_type
protected

Definition at line 73 of file bootstrap_file.h.

Member Function Documentation

◆ close()

bool BootstrapFile::close ( )
protected

Definition at line 253 of file bootstrap_file.cpp.

254{
255 if (m_raw_data_file->fail())
256 return false;
257
258 m_raw_data_file->flush();
259 delete m_output_stream;
260 delete m_raw_data_file;
261 return true;
262}
std::ofstream * m_raw_data_file
boost::iostreams::stream< boost::iostreams::back_insert_device< buffer_type > > * m_output_stream
Here is the caller graph for this function:

◆ count_blocks() [1/2]

uint64_t BootstrapFile::count_blocks ( const std::string & dir_path)

Definition at line 436 of file bootstrap_file.cpp.

437{
438 std::streampos dummy_pos;
439 uint64_t dummy_height = 0;
440 return count_blocks(import_file_path, dummy_pos, dummy_height);
441}
uint64_t count_blocks(const std::string &dir_path, std::streampos &start_pos, uint64_t &seek_height)
unsigned __int64 uint64_t
Definition stdint.h:136
Here is the call graph for this function:

◆ count_blocks() [2/2]

uint64_t BootstrapFile::count_blocks ( const std::string & dir_path,
std::streampos & start_pos,
uint64_t & seek_height )

Definition at line 446 of file bootstrap_file.cpp.

447{
448 boost::filesystem::path raw_file_path(import_file_path);
449 boost::system::error_code ec;
450 if (!boost::filesystem::exists(raw_file_path, ec))
451 {
452 MFATAL("bootstrap file not found: " << raw_file_path);
453 throw std::runtime_error("Aborting");
454 }
455 std::ifstream import_file;
456 import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in);
457
458 uint64_t start_height = seek_height;
459 uint64_t h = 0;
460 if (import_file.fail())
461 {
462 MFATAL("import_file.open() fail");
463 throw std::runtime_error("Aborting");
464 }
465
466 uint64_t full_header_size; // 4 byte magic + length of header structures
467 uint8_t major_version, minor_version;
468 full_header_size = seek_to_first_chunk(import_file, major_version, minor_version);
469
470 MINFO("Scanning blockchain from bootstrap file...");
471 bool quit = false;
472 uint64_t bytes_read = 0, blocks;
473 int progress_interval = 10;
474
475 while (! quit)
476 {
477 if (start_height && h + progress_interval >= start_height - 1)
478 {
479 start_height = 0;
480 start_pos = import_file.tellg();
481 seek_height = h;
482 }
483 bytes_read += count_bytes(import_file, progress_interval, blocks, quit);
484 h += blocks;
485 std::cout << "\r" << "block height: " << h-1 <<
486 " \r" <<
487 std::flush;
488
489 // std::cout << refresh_string;
490 MDEBUG("Number bytes scanned: " << bytes_read);
491 }
492
493 import_file.close();
494
495 std::cout << ENDL;
496 std::cout << "Done scanning bootstrap file" << ENDL;
497 std::cout << "Full header length: " << full_header_size << " bytes" << ENDL;
498 std::cout << "Scanned for blocks: " << bytes_read << " bytes" << ENDL;
499 std::cout << "Total: " << full_header_size + bytes_read << " bytes" << ENDL;
500 std::cout << "Number of blocks: " << h << ENDL;
501 std::cout << ENDL;
502
503 // NOTE: h is the number of blocks.
504 // Note that a block's stored height is zero-based, but parts of the code use
505 // one-based height.
506 return h;
507}
uint64_t count_bytes(std::ifstream &import_file, uint64_t blocks, uint64_t &h, bool &quit)
uint64_t seek_to_first_chunk(std::ifstream &import_file, uint8_t &major_version, uint8_t &minor_version)
#define MFATAL(x)
Definition misc_log_ex.h:72
#define MDEBUG(x)
Definition misc_log_ex.h:76
#define ENDL
#define MINFO(x)
Definition misc_log_ex.h:75
unsigned char uint8_t
Definition stdint.h:124
Here is the call graph for this function:
Here is the caller graph for this function:

◆ count_bytes()

uint64_t BootstrapFile::count_bytes ( std::ifstream & import_file,
uint64_t blocks,
uint64_t & h,
bool & quit )

Definition at line 380 of file bootstrap_file.cpp.

381{
382 uint64_t bytes_read = 0;
383 uint32_t chunk_size;
384 char buf1[sizeof(chunk_size)];
385 std::string str1;
386 h = 0;
387 while (1)
388 {
389 import_file.read(buf1, sizeof(chunk_size));
390 if (!import_file) {
391 std::cout << refresh_string;
392 MDEBUG("End of file reached");
393 quit = true;
394 break;
395 }
396 bytes_read += sizeof(chunk_size);
397 str1.assign(buf1, sizeof(chunk_size));
398 if (! ::serialization::parse_binary(str1, chunk_size))
399 throw std::runtime_error("Error in deserialization of chunk_size");
400 MDEBUG("chunk_size: " << chunk_size);
401
402 if (chunk_size > BUFFER_SIZE)
403 {
404 std::cout << refresh_string;
405 MWARNING("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE
406 << " height: " << h-1 << ", offset " << bytes_read);
407 throw std::runtime_error("Aborting: chunk size exceeds buffer size");
408 }
409 if (chunk_size > CHUNK_SIZE_WARNING_THRESHOLD)
410 {
411 std::cout << refresh_string;
412 MDEBUG("NOTE: chunk_size " << chunk_size << " > " << CHUNK_SIZE_WARNING_THRESHOLD << " << height: "
413 << h-1 << ", offset " << bytes_read);
414 }
415 else if (chunk_size <= 0) {
416 std::cout << refresh_string;
417 MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1 << ", offset " << bytes_read);
418 throw std::runtime_error("Aborting");
419 }
420 // skip to next expected block size value
421 import_file.seekg(chunk_size, std::ios_base::cur);
422 if (! import_file) {
423 std::cout << refresh_string;
424 MFATAL("ERROR: unexpected end of file: bytes read before error: "
425 << import_file.gcount() << " of chunk_size " << chunk_size);
426 throw std::runtime_error("Aborting");
427 }
428 bytes_read += chunk_size;
430 if (h >= blocks)
431 break;
432 }
433 return bytes_read;
434}
#define CHUNK_SIZE_WARNING_THRESHOLD
#define BUFFER_SIZE
#define NUM_BLOCKS_PER_CHUNK
#define MWARNING(x)
Definition misc_log_ex.h:74
bool parse_binary(const std::string &blob, T &v)
unsigned int uint32_t
Definition stdint.h:126
Here is the call graph for this function:
Here is the caller graph for this function:

◆ flush_chunk()

void BootstrapFile::flush_chunk ( )
protected

Definition at line 172 of file bootstrap_file.cpp.

173{
174 m_output_stream->flush();
175
176 uint32_t chunk_size = m_buffer.size();
177 // MTRACE("chunk_size " << chunk_size);
178 if (chunk_size > BUFFER_SIZE)
179 {
180 MWARNING("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE);
181 }
182
183 std::string blob;
184 if (! ::serialization::dump_binary(chunk_size, blob))
185 {
186 throw std::runtime_error("Error in serialization of chunk size");
187 }
188 *m_raw_data_file << blob;
189
190 if (m_max_chunk < chunk_size)
191 {
192 m_max_chunk = chunk_size;
193 }
194 long pos_before = m_raw_data_file->tellp();
195 std::copy(m_buffer.begin(), m_buffer.end(), std::ostreambuf_iterator<char>(*m_raw_data_file));
196 m_raw_data_file->flush();
197 long pos_after = m_raw_data_file->tellp();
198 long num_chars_written = pos_after - pos_before;
199 if (static_cast<unsigned long>(num_chars_written) != chunk_size)
200 {
201 MFATAL("Error writing chunk: height: " << m_cur_height << " chunk_size: " << chunk_size << " num chars written: " << num_chars_written);
202 throw std::runtime_error("Error writing chunk");
203 }
204
205 m_buffer.clear();
206 delete m_output_stream;
207 m_output_stream = new boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type>>(m_buffer);
208 MDEBUG("flushed chunk: chunk_size: " << chunk_size);
209}
buffer_type m_buffer
bool dump_binary(T &v, std::string &blob)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ initialize_file()

bool BootstrapFile::initialize_file ( )
protected

Definition at line 116 of file bootstrap_file.cpp.

117{
118 const uint32_t file_magic = blockchain_raw_magic;
119
120 std::string blob;
121 if (! ::serialization::dump_binary(file_magic, blob))
122 {
123 throw std::runtime_error("Error in serialization of file magic");
124 }
125 *m_raw_data_file << blob;
126
127 bootstrap::file_info bfi;
128 bfi.major_version = 1;
129 bfi.minor_version = 0;
130 bfi.header_size = header_size;
131
132 bootstrap::blocks_info bbi;
133 bbi.block_first = 0;
134 bbi.block_last = 0;
135 bbi.block_last_pos = 0;
136
137 buffer_type buffer2;
138 boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type>> output_stream_header(buffer2);
139
140 uint32_t bd_size = 0;
141
143 MDEBUG("bootstrap::file_info size: " << bd.size());
144 bd_size = bd.size();
145
146 if (! ::serialization::dump_binary(bd_size, blob))
147 {
148 throw std::runtime_error("Error in serialization of bootstrap::file_info size");
149 }
150 output_stream_header << blob;
151 output_stream_header << bd;
152
154 MDEBUG("bootstrap::blocks_info size: " << bd.size());
155 bd_size = bd.size();
156
157 if (! ::serialization::dump_binary(bd_size, blob))
158 {
159 throw std::runtime_error("Error in serialization of bootstrap::blocks_info size");
160 }
161 output_stream_header << blob;
162 output_stream_header << bd;
163
164 output_stream_header.flush();
165 output_stream_header << std::string(header_size-buffer2.size(), 0); // fill in rest with null bytes
166 output_stream_header.flush();
167 std::copy(buffer2.begin(), buffer2.end(), std::ostreambuf_iterator<char>(*m_raw_data_file));
168
169 return true;
170}
std::vector< char > buffer_type
std::string blobdata
bool t_serializable_object_to_blob(const t_object &to, blobdata &b_blob)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_writer()

bool BootstrapFile::open_writer ( const boost::filesystem::path & file_path)
protected

Definition at line 56 of file bootstrap_file.cpp.

57{
58 const boost::filesystem::path dir_path = file_path.parent_path();
59 if (!dir_path.empty())
60 {
61 if (boost::filesystem::exists(dir_path))
62 {
63 if (!boost::filesystem::is_directory(dir_path))
64 {
65 MFATAL("export directory path is a file: " << dir_path);
66 return false;
67 }
68 }
69 else
70 {
71 if (!boost::filesystem::create_directory(dir_path))
72 {
73 MFATAL("Failed to create directory " << dir_path);
74 return false;
75 }
76 }
77 }
78
79 m_raw_data_file = new std::ofstream();
80
81 bool do_initialize_file = false;
83
84 if (! boost::filesystem::exists(file_path))
85 {
86 MDEBUG("creating file");
87 do_initialize_file = true;
88 num_blocks = 0;
89 }
90 else
91 {
92 num_blocks = count_blocks(file_path.string());
93 MDEBUG("appending to existing file with height: " << num_blocks-1 << " total blocks: " << num_blocks);
94 }
95 m_height = num_blocks;
96
97 if (do_initialize_file)
98 m_raw_data_file->open(file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::trunc);
99 else
100 m_raw_data_file->open(file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::app | std::ios::ate);
101
102 if (m_raw_data_file->fail())
103 return false;
104
105 m_output_stream = new boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type>>(m_buffer);
106 if (m_output_stream == nullptr)
107 return false;
108
109 if (do_initialize_file)
111
112 return true;
113}
uint64_t num_blocks(const std::vector< test_event_entry > &events)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ seek_to_first_chunk()

uint64_t BootstrapFile::seek_to_first_chunk ( std::ifstream & import_file,
uint8_t & major_version,
uint8_t & minor_version )

Definition at line 327 of file bootstrap_file.cpp.

328{
329 uint32_t file_magic;
330
331 std::string str1;
332 char buf1[2048];
333 import_file.read(buf1, sizeof(file_magic));
334 if (! import_file)
335 throw std::runtime_error("Error reading expected number of bytes");
336 str1.assign(buf1, sizeof(file_magic));
337
338 if (! ::serialization::parse_binary(str1, file_magic))
339 throw std::runtime_error("Error in deserialization of file_magic");
340
341 if (file_magic != blockchain_raw_magic)
342 {
343 MFATAL("bootstrap file not recognized");
344 throw std::runtime_error("Aborting");
345 }
346 else
347 MINFO("bootstrap file recognized");
348
349 uint32_t buflen_file_info;
350
351 import_file.read(buf1, sizeof(buflen_file_info));
352 str1.assign(buf1, sizeof(buflen_file_info));
353 if (! import_file)
354 throw std::runtime_error("Error reading expected number of bytes");
355 if (! ::serialization::parse_binary(str1, buflen_file_info))
356 throw std::runtime_error("Error in deserialization of buflen_file_info");
357 MINFO("bootstrap::file_info size: " << buflen_file_info);
358
359 if (buflen_file_info > sizeof(buf1))
360 throw std::runtime_error("Error: bootstrap::file_info size exceeds buffer size");
361 import_file.read(buf1, buflen_file_info);
362 if (! import_file)
363 throw std::runtime_error("Error reading expected number of bytes");
364 str1.assign(buf1, buflen_file_info);
365 bootstrap::file_info bfi;
366 if (! ::serialization::parse_binary(str1, bfi))
367 throw std::runtime_error("Error in deserialization of bootstrap::file_info");
368 MINFO("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version));
369 MINFO("bootstrap magic size: " << sizeof(file_magic));
370 MINFO("bootstrap header size: " << bfi.header_size);
371
372 uint64_t full_header_size = sizeof(file_magic) + bfi.header_size;
373 import_file.seekg(full_header_size);
374
375 major_version = bfi.major_version;
376 minor_version = bfi.minor_version;
377 return full_header_size;
378}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_blockchain_raw()

bool BootstrapFile::store_blockchain_raw ( cryptonote::Blockchain * cs,
cryptonote::tx_memory_pool * txp,
boost::filesystem::path & output_file,
uint64_t use_block_height = 0 )

Definition at line 265 of file bootstrap_file.cpp.

266{
267 uint64_t num_blocks_written = 0;
268 m_max_chunk = 0;
269 m_blockchain_storage = _blockchain_storage;
270 m_tx_pool = _tx_pool;
271 uint64_t progress_interval = 100;
272 MINFO("Storing blocks raw data...");
273 if (!BootstrapFile::open_writer(output_file))
274 {
275 MFATAL("failed to open raw file for write");
276 return false;
277 }
278 block b;
279
280 // block_start, block_stop use 0-based height. m_height uses 1-based height. So to resume export
281 // from last exported block, block_start doesn't need to add 1 here, as it's already at the next
282 // height.
283 uint64_t block_start = m_height;
284 uint64_t block_stop = 0;
285 MINFO("source blockchain height: " << m_blockchain_storage->get_current_blockchain_height()-1);
286 if ((requested_block_stop > 0) && (requested_block_stop < m_blockchain_storage->get_current_blockchain_height()))
287 {
288 MINFO("Using requested block height: " << requested_block_stop);
289 block_stop = requested_block_stop;
290 }
291 else
292 {
293 block_stop = m_blockchain_storage->get_current_blockchain_height() - 1;
294 MINFO("Using block height of source blockchain: " << block_stop);
295 }
296 for (m_cur_height = block_start; m_cur_height <= block_stop; ++m_cur_height)
297 {
298 // this method's height refers to 0-based height (genesis block = height 0)
299 crypto::hash hash = m_blockchain_storage->get_block_id_by_height(m_cur_height);
300 m_blockchain_storage->get_block_by_hash(hash, b);
301 write_block(b);
302 if (m_cur_height % NUM_BLOCKS_PER_CHUNK == 0) {
303 flush_chunk();
304 num_blocks_written += NUM_BLOCKS_PER_CHUNK;
305 }
306 if (m_cur_height % progress_interval == 0) {
307 std::cout << refresh_string;
308 std::cout << "block " << m_cur_height << "/" << block_stop << "\r" << std::flush;
309 }
310 }
311 // NOTE: use of NUM_BLOCKS_PER_CHUNK is a placeholder in case multi-block chunks are later supported.
312 if (m_cur_height % NUM_BLOCKS_PER_CHUNK != 0)
313 {
314 flush_chunk();
315 }
316 // print message for last block, which may not have been printed yet due to progress_interval
317 std::cout << refresh_string;
318 std::cout << "block " << m_cur_height-1 << "/" << block_stop << ENDL;
319
320 MINFO("Number of blocks exported: " << num_blocks_written);
321 if (num_blocks_written > 0)
322 MINFO("Largest chunk: " << m_max_chunk << " bytes");
323
324 return BootstrapFile::close();
325}
void write_block(block &block)
tx_memory_pool * m_tx_pool
Blockchain * m_blockchain_storage
bool open_writer(const boost::filesystem::path &file_path)
POD_CLASS hash
Definition hash.h:50
Here is the call graph for this function:

◆ write_block()

void BootstrapFile::write_block ( block & block)
protected

Definition at line 211 of file bootstrap_file.cpp.

212{
213 bootstrap::block_package bp;
214 bp.block = block;
215
216 std::vector<transaction> txs;
217
218 uint64_t block_height = boost::get<txin_gen>(block.miner_tx.vin.front()).height;
219
220
221 // now add all regular transactions
222 for (const auto& tx_id : block.tx_hashes)
223 {
224 if (tx_id == crypto::null_hash)
225 {
226 throw std::runtime_error("Aborting: tx == null_hash");
227 }
228 transaction tx = m_blockchain_storage->get_db().get_tx(tx_id);
229
230 txs.push_back(tx);
231 }
232
233 // these non-coinbase txs will be serialized using this structure
234 bp.txs = txs;
235
236 // These three attributes are currently necessary for a fast import that adds blocks without verification.
237 bool include_extra_block_data = true;
238 if (include_extra_block_data)
239 {
240 size_t block_weight = m_blockchain_storage->get_db().get_block_weight(block_height);
241 difficulty_type cumulative_difficulty = m_blockchain_storage->get_db().get_block_cumulative_difficulty(block_height);
242 uint64_t coins_generated = m_blockchain_storage->get_db().get_block_already_generated_coins(block_height);
243
244 bp.block_weight = block_weight;
245 bp.cumulative_difficulty = cumulative_difficulty;
246 bp.coins_generated = coins_generated;
247 }
248
250 m_output_stream->write((const char*)bd.data(), bd.size());
251}
boost::multiprecision::uint128_t difficulty_type
Definition difficulty.h:43
std::vector< crypto::hash > tx_hashes
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_blockchain_storage

Blockchain* BootstrapFile::m_blockchain_storage
protected

Definition at line 70 of file bootstrap_file.h.

◆ m_buffer

buffer_type BootstrapFile::m_buffer
protected

Definition at line 75 of file bootstrap_file.h.

◆ m_output_stream

boost::iostreams::stream<boost::iostreams::back_insert_device<buffer_type> >* BootstrapFile::m_output_stream
protected

Definition at line 76 of file bootstrap_file.h.

◆ m_raw_data_file

std::ofstream* BootstrapFile::m_raw_data_file
protected

Definition at line 74 of file bootstrap_file.h.

◆ m_tx_pool

tx_memory_pool* BootstrapFile::m_tx_pool
protected

Definition at line 72 of file bootstrap_file.h.


The documentation for this class was generated from the following files:
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/blockchain_utilities/bootstrap_file.h
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/blockchain_utilities/bootstrap_file.cpp